blob: 0acb428d7a3bc85cbd9a2f2d802d97a4fd842e78 [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
bsalomon8e74f802016-01-30 10:01:40 -08008#include <functional>
bsalomon0d996862016-03-09 18:44:43 -08009#include <initializer_list>
ericrkb4da01d2016-06-13 11:18:14 -070010#include <vector>
bsalomon8e74f802016-01-30 10:01:40 -080011
robertphillipsc5035e72016-03-17 06:58:39 -070012#include "SkAutoPixmapStorage.h"
halcanaryc56c6ef2015-09-28 11:55:28 -070013#include "SkBitmap.h"
reed871872f2015-06-22 12:48:26 -070014#include "SkCanvas.h"
15#include "SkData.h"
reed871872f2015-06-22 12:48:26 -070016#include "SkImageEncoder.h"
kkinnunen7b94c142015-11-24 07:39:40 -080017#include "SkImageGenerator.h"
reed871872f2015-06-22 12:48:26 -070018#include "SkImage_Base.h"
reed2dad7692016-08-01 11:12:58 -070019#include "SkImagePriv.h"
fmalitac3470342015-09-04 11:36:39 -070020#include "SkPicture.h"
21#include "SkPictureRecorder.h"
fmalita2be71252015-09-03 07:17:25 -070022#include "SkPixelSerializer.h"
reed871872f2015-06-22 12:48:26 -070023#include "SkRRect.h"
fmalitac3470342015-09-04 11:36:39 -070024#include "SkStream.h"
reed871872f2015-06-22 12:48:26 -070025#include "SkSurface.h"
26#include "SkUtils.h"
27#include "Test.h"
28
brianosmandb2cb102016-07-22 07:22:04 -070029#if SK_SUPPORT_GPU
30#include "GrGpu.h"
31#endif
32
bsalomonf2f1c172016-04-05 12:59:06 -070033using namespace sk_gpu_test;
bsalomon3724e572016-03-30 18:56:19 -070034
reed871872f2015-06-22 12:48:26 -070035static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect* subsetA,
36 SkImage* b) {
37 const int widthA = subsetA ? subsetA->width() : a->width();
38 const int heightA = subsetA ? subsetA->height() : a->height();
39
40 REPORTER_ASSERT(reporter, widthA == b->width());
41 REPORTER_ASSERT(reporter, heightA == b->height());
reed1cb36462016-03-09 15:21:32 -080042
43 // see https://bug.skia.org/3965
44 //REPORTER_ASSERT(reporter, a->isOpaque() == b->isOpaque());
reed871872f2015-06-22 12:48:26 -070045
brianosman69c166d2016-08-17 14:01:05 -070046 SkImageInfo info = SkImageInfo::MakeN32(widthA, heightA, a->alphaType());
reed871872f2015-06-22 12:48:26 -070047 SkAutoPixmapStorage pmapA, pmapB;
48 pmapA.alloc(info);
49 pmapB.alloc(info);
50
51 const int srcX = subsetA ? subsetA->x() : 0;
52 const int srcY = subsetA ? subsetA->y() : 0;
53
54 REPORTER_ASSERT(reporter, a->readPixels(pmapA, srcX, srcY));
55 REPORTER_ASSERT(reporter, b->readPixels(pmapB, 0, 0));
56
57 const size_t widthBytes = widthA * info.bytesPerPixel();
58 for (int y = 0; y < heightA; ++y) {
59 REPORTER_ASSERT(reporter, !memcmp(pmapA.addr32(0, y), pmapB.addr32(0, y), widthBytes));
60 }
61}
kkinnunen7b94c142015-11-24 07:39:40 -080062static void draw_image_test_pattern(SkCanvas* canvas) {
reed871872f2015-06-22 12:48:26 -070063 canvas->clear(SK_ColorWHITE);
reed871872f2015-06-22 12:48:26 -070064 SkPaint paint;
65 paint.setColor(SK_ColorBLACK);
kkinnunen7b94c142015-11-24 07:39:40 -080066 canvas->drawRect(SkRect::MakeXYWH(5, 5, 10, 10), paint);
67}
reed9ce9d672016-03-17 10:51:11 -070068static sk_sp<SkImage> create_image() {
kkinnunen7b94c142015-11-24 07:39:40 -080069 const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
reede8f30622016-03-23 18:59:25 -070070 auto surface(SkSurface::MakeRaster(info));
kkinnunen7b94c142015-11-24 07:39:40 -080071 draw_image_test_pattern(surface->getCanvas());
reed9ce9d672016-03-17 10:51:11 -070072 return surface->makeImageSnapshot();
reed871872f2015-06-22 12:48:26 -070073}
bungeman38d909e2016-08-02 14:40:46 -070074static sk_sp<SkData> create_image_data(SkImageInfo* info) {
scroggo9d081722016-04-20 08:27:18 -070075 *info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
76 const size_t rowBytes = info->minRowBytes();
bungeman38d909e2016-08-02 14:40:46 -070077 sk_sp<SkData> data(SkData::MakeUninitialized(rowBytes * info->height()));
scroggo9d081722016-04-20 08:27:18 -070078 {
79 SkBitmap bm;
80 bm.installPixels(*info, data->writable_data(), rowBytes);
81 SkCanvas canvas(bm);
82 draw_image_test_pattern(&canvas);
83 }
bungeman38d909e2016-08-02 14:40:46 -070084 return data;
scroggo9d081722016-04-20 08:27:18 -070085}
86static sk_sp<SkImage> create_data_image() {
87 SkImageInfo info;
88 sk_sp<SkData> data(create_image_data(&info));
bungeman38d909e2016-08-02 14:40:46 -070089 return SkImage::MakeRasterData(info, std::move(data), info.minRowBytes());
scroggo9d081722016-04-20 08:27:18 -070090}
91#if SK_SUPPORT_GPU // not gpu-specific but currently only used in GPU tests
reed9ce9d672016-03-17 10:51:11 -070092static sk_sp<SkImage> create_image_565() {
bsalomon0d996862016-03-09 18:44:43 -080093 const SkImageInfo info = SkImageInfo::Make(20, 20, kRGB_565_SkColorType, kOpaque_SkAlphaType);
reede8f30622016-03-23 18:59:25 -070094 auto surface(SkSurface::MakeRaster(info));
bsalomon0d996862016-03-09 18:44:43 -080095 draw_image_test_pattern(surface->getCanvas());
reed9ce9d672016-03-17 10:51:11 -070096 return surface->makeImageSnapshot();
bsalomon0d996862016-03-09 18:44:43 -080097}
bsalomond4907082016-06-13 12:13:03 -070098static sk_sp<SkImage> create_image_large() {
99 const SkImageInfo info = SkImageInfo::MakeN32(32000, 32, kOpaque_SkAlphaType);
100 auto surface(SkSurface::MakeRaster(info));
101 surface->getCanvas()->clear(SK_ColorWHITE);
102 SkPaint paint;
103 paint.setColor(SK_ColorBLACK);
104 surface->getCanvas()->drawRect(SkRect::MakeXYWH(4000, 2, 28000, 30), paint);
105 return surface->makeImageSnapshot();
106}
reed9ce9d672016-03-17 10:51:11 -0700107static sk_sp<SkImage> create_image_ct() {
bsalomon0d996862016-03-09 18:44:43 -0800108 SkPMColor colors[] = {
109 SkPreMultiplyARGB(0xFF, 0xFF, 0xFF, 0x00),
110 SkPreMultiplyARGB(0x80, 0x00, 0xA0, 0xFF),
111 SkPreMultiplyARGB(0xFF, 0xBB, 0x00, 0xBB)
112 };
Hal Canary342b7ac2016-11-04 11:49:42 -0400113 sk_sp<SkColorTable> colorTable(new SkColorTable(colors, SK_ARRAY_COUNT(colors)));
bsalomon0d996862016-03-09 18:44:43 -0800114 uint8_t data[] = {
115 0, 0, 0, 0, 0,
116 0, 1, 1, 1, 0,
117 0, 1, 2, 1, 0,
118 0, 1, 1, 1, 0,
119 0, 0, 0, 0, 0
120 };
121 SkImageInfo info = SkImageInfo::Make(5, 5, kIndex_8_SkColorType, kPremul_SkAlphaType);
Hal Canary342b7ac2016-11-04 11:49:42 -0400122 return SkImage::MakeRasterCopy(SkPixmap(info, data, 5, colorTable.get()));
bsalomon0d996862016-03-09 18:44:43 -0800123}
reed9ce9d672016-03-17 10:51:11 -0700124static sk_sp<SkImage> create_picture_image() {
bsalomon8e74f802016-01-30 10:01:40 -0800125 SkPictureRecorder recorder;
126 SkCanvas* canvas = recorder.beginRecording(10, 10);
127 canvas->clear(SK_ColorCYAN);
reedca2622b2016-03-18 07:25:55 -0700128 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(), SkISize::Make(10, 10),
129 nullptr, nullptr);
bsalomon8e74f802016-01-30 10:01:40 -0800130};
131#endif
kkinnunen7b94c142015-11-24 07:39:40 -0800132// Want to ensure that our Release is called when the owning image is destroyed
133struct RasterDataHolder {
134 RasterDataHolder() : fReleaseCount(0) {}
bungeman38d909e2016-08-02 14:40:46 -0700135 sk_sp<SkData> fData;
kkinnunen7b94c142015-11-24 07:39:40 -0800136 int fReleaseCount;
137 static void Release(const void* pixels, void* context) {
138 RasterDataHolder* self = static_cast<RasterDataHolder*>(context);
139 self->fReleaseCount++;
140 self->fData.reset();
141 }
142};
reed9ce9d672016-03-17 10:51:11 -0700143static sk_sp<SkImage> create_rasterproc_image(RasterDataHolder* dataHolder) {
kkinnunen7b94c142015-11-24 07:39:40 -0800144 SkASSERT(dataHolder);
145 SkImageInfo info;
bungeman38d909e2016-08-02 14:40:46 -0700146 dataHolder->fData = create_image_data(&info);
147 return SkImage::MakeFromRaster(SkPixmap(info, dataHolder->fData->data(), info.minRowBytes()),
reed9ce9d672016-03-17 10:51:11 -0700148 RasterDataHolder::Release, dataHolder);
kkinnunen7b94c142015-11-24 07:39:40 -0800149}
reed9ce9d672016-03-17 10:51:11 -0700150static sk_sp<SkImage> create_codec_image() {
kkinnunen7b94c142015-11-24 07:39:40 -0800151 SkImageInfo info;
bungeman38d909e2016-08-02 14:40:46 -0700152 sk_sp<SkData> data(create_image_data(&info));
kkinnunen7b94c142015-11-24 07:39:40 -0800153 SkBitmap bitmap;
154 bitmap.installPixels(info, data->writable_data(), info.minRowBytes());
bungeman38d909e2016-08-02 14:40:46 -0700155 sk_sp<SkData> src(SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100));
156 return SkImage::MakeFromEncoded(std::move(src));
kkinnunen7b94c142015-11-24 07:39:40 -0800157}
158#if SK_SUPPORT_GPU
reed9ce9d672016-03-17 10:51:11 -0700159static sk_sp<SkImage> create_gpu_image(GrContext* context) {
kkinnunen7b94c142015-11-24 07:39:40 -0800160 const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
reede8f30622016-03-23 18:59:25 -0700161 auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info));
kkinnunen7b94c142015-11-24 07:39:40 -0800162 draw_image_test_pattern(surface->getCanvas());
reed9ce9d672016-03-17 10:51:11 -0700163 return surface->makeImageSnapshot();
kkinnunen7b94c142015-11-24 07:39:40 -0800164}
165#endif
reed871872f2015-06-22 12:48:26 -0700166
kkinnunen7b94c142015-11-24 07:39:40 -0800167static void test_encode(skiatest::Reporter* reporter, SkImage* image) {
reed871872f2015-06-22 12:48:26 -0700168 const SkIRect ir = SkIRect::MakeXYWH(5, 5, 10, 10);
reed9ce9d672016-03-17 10:51:11 -0700169 sk_sp<SkData> origEncoded(image->encode());
reed871872f2015-06-22 12:48:26 -0700170 REPORTER_ASSERT(reporter, origEncoded);
171 REPORTER_ASSERT(reporter, origEncoded->size() > 0);
172
reed9ce9d672016-03-17 10:51:11 -0700173 sk_sp<SkImage> decoded(SkImage::MakeFromEncoded(origEncoded));
scroggo8e6c7ad2016-09-16 08:20:38 -0700174 if (!decoded) {
175 ERRORF(reporter, "failed to decode image!");
176 return;
177 }
reed871872f2015-06-22 12:48:26 -0700178 REPORTER_ASSERT(reporter, decoded);
reed9ce9d672016-03-17 10:51:11 -0700179 assert_equal(reporter, image, nullptr, decoded.get());
reed871872f2015-06-22 12:48:26 -0700180
181 // Now see if we can instantiate an image from a subset of the surface/origEncoded
mtklein5f939ab2016-03-16 10:28:35 -0700182
reed9ce9d672016-03-17 10:51:11 -0700183 decoded = SkImage::MakeFromEncoded(origEncoded, &ir);
reed871872f2015-06-22 12:48:26 -0700184 REPORTER_ASSERT(reporter, decoded);
reed9ce9d672016-03-17 10:51:11 -0700185 assert_equal(reporter, image, &ir, decoded.get());
reed871872f2015-06-22 12:48:26 -0700186}
187
kkinnunen7b94c142015-11-24 07:39:40 -0800188DEF_TEST(ImageEncode, reporter) {
reed9ce9d672016-03-17 10:51:11 -0700189 test_encode(reporter, create_image().get());
reed871872f2015-06-22 12:48:26 -0700190}
191
192#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700193DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageEncode_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700194 test_encode(reporter, create_gpu_image(ctxInfo.grContext()).get());
reed871872f2015-06-22 12:48:26 -0700195}
196#endif
reed759373a2015-07-03 21:01:10 -0700197
reed2dad7692016-08-01 11:12:58 -0700198DEF_TEST(Image_MakeFromRasterBitmap, reporter) {
199 const struct {
reed1ec04d92016-08-05 12:07:41 -0700200 SkCopyPixelsMode fCPM;
201 bool fExpectSameAsMutable;
202 bool fExpectSameAsImmutable;
reed2dad7692016-08-01 11:12:58 -0700203 } recs[] = {
reed1ec04d92016-08-05 12:07:41 -0700204 { kIfMutable_SkCopyPixelsMode, false, true },
205 { kAlways_SkCopyPixelsMode, false, false },
206 { kNever_SkCopyPixelsMode, true, true },
reed2dad7692016-08-01 11:12:58 -0700207 };
208 for (auto rec : recs) {
209 SkPixmap pm;
210 SkBitmap bm;
211 bm.allocN32Pixels(100, 100);
212
reed1ec04d92016-08-05 12:07:41 -0700213 auto img = SkMakeImageFromRasterBitmap(bm, rec.fCPM);
reed2dad7692016-08-01 11:12:58 -0700214 REPORTER_ASSERT(reporter, img->peekPixels(&pm));
215 const bool sameMutable = pm.addr32(0, 0) == bm.getAddr32(0, 0);
216 REPORTER_ASSERT(reporter, rec.fExpectSameAsMutable == sameMutable);
reedae296442016-08-05 13:19:01 -0700217 REPORTER_ASSERT(reporter, (bm.getGenerationID() == img->uniqueID()) == sameMutable);
reed2dad7692016-08-01 11:12:58 -0700218
219 bm.notifyPixelsChanged(); // force a new generation ID
220
221 bm.setImmutable();
reed1ec04d92016-08-05 12:07:41 -0700222 img = SkMakeImageFromRasterBitmap(bm, rec.fCPM);
reed2dad7692016-08-01 11:12:58 -0700223 REPORTER_ASSERT(reporter, img->peekPixels(&pm));
224 const bool sameImmutable = pm.addr32(0, 0) == bm.getAddr32(0, 0);
225 REPORTER_ASSERT(reporter, rec.fExpectSameAsImmutable == sameImmutable);
reedae296442016-08-05 13:19:01 -0700226 REPORTER_ASSERT(reporter, (bm.getGenerationID() == img->uniqueID()) == sameImmutable);
reed2dad7692016-08-01 11:12:58 -0700227 }
228}
229
fmalita2be71252015-09-03 07:17:25 -0700230namespace {
231
232const char* kSerializedData = "serialized";
233
234class MockSerializer : public SkPixelSerializer {
fmalitac3470342015-09-04 11:36:39 -0700235public:
bungeman38d909e2016-08-02 14:40:46 -0700236 MockSerializer(sk_sp<SkData> (*func)()) : fFunc(func), fDidEncode(false) { }
fmalitac3470342015-09-04 11:36:39 -0700237
238 bool didEncode() const { return fDidEncode; }
239
fmalita2be71252015-09-03 07:17:25 -0700240protected:
reedc9e190d2015-09-28 09:58:41 -0700241 bool onUseEncodedData(const void*, size_t) override {
242 return false;
fmalita2be71252015-09-03 07:17:25 -0700243 }
244
halcanary99073712015-12-10 09:30:57 -0800245 SkData* onEncode(const SkPixmap&) override {
fmalitac3470342015-09-04 11:36:39 -0700246 fDidEncode = true;
bungeman38d909e2016-08-02 14:40:46 -0700247 return fFunc().release();
fmalita2be71252015-09-03 07:17:25 -0700248 }
fmalitac3470342015-09-04 11:36:39 -0700249
250private:
bungeman38d909e2016-08-02 14:40:46 -0700251 sk_sp<SkData> (*fFunc)();
fmalitac3470342015-09-04 11:36:39 -0700252 bool fDidEncode;
253
254 typedef SkPixelSerializer INHERITED;
fmalita2be71252015-09-03 07:17:25 -0700255};
256
257} // anonymous namespace
258
259// Test that SkImage encoding observes custom pixel serializers.
260DEF_TEST(Image_Encode_Serializer, reporter) {
bungeman38d909e2016-08-02 14:40:46 -0700261 MockSerializer serializer([]() -> sk_sp<SkData> {
262 return SkData::MakeWithCString(kSerializedData);
263 });
reed9ce9d672016-03-17 10:51:11 -0700264 sk_sp<SkImage> image(create_image());
bungeman38d909e2016-08-02 14:40:46 -0700265 sk_sp<SkData> encoded(image->encode(&serializer));
266 sk_sp<SkData> reference(SkData::MakeWithCString(kSerializedData));
fmalita2be71252015-09-03 07:17:25 -0700267
fmalitac3470342015-09-04 11:36:39 -0700268 REPORTER_ASSERT(reporter, serializer.didEncode());
fmalita2be71252015-09-03 07:17:25 -0700269 REPORTER_ASSERT(reporter, encoded);
270 REPORTER_ASSERT(reporter, encoded->size() > 0);
bungeman38d909e2016-08-02 14:40:46 -0700271 REPORTER_ASSERT(reporter, encoded->equals(reference.get()));
fmalita2be71252015-09-03 07:17:25 -0700272}
273
fmalitac3470342015-09-04 11:36:39 -0700274// Test that image encoding failures do not break picture serialization/deserialization.
275DEF_TEST(Image_Serialize_Encoding_Failure, reporter) {
reede8f30622016-03-23 18:59:25 -0700276 auto surface(SkSurface::MakeRasterN32Premul(100, 100));
fmalitac3470342015-09-04 11:36:39 -0700277 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700278 sk_sp<SkImage> image(surface->makeImageSnapshot());
fmalitac3470342015-09-04 11:36:39 -0700279 REPORTER_ASSERT(reporter, image);
280
281 SkPictureRecorder recorder;
282 SkCanvas* canvas = recorder.beginRecording(100, 100);
283 canvas->drawImage(image, 0, 0);
reedca2622b2016-03-18 07:25:55 -0700284 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
fmalitac3470342015-09-04 11:36:39 -0700285 REPORTER_ASSERT(reporter, picture);
286 REPORTER_ASSERT(reporter, picture->approximateOpCount() > 0);
287
bungeman38d909e2016-08-02 14:40:46 -0700288 MockSerializer emptySerializer([]() -> sk_sp<SkData> { return SkData::MakeEmpty(); });
289 MockSerializer nullSerializer([]() -> sk_sp<SkData> { return nullptr; });
fmalitac3470342015-09-04 11:36:39 -0700290 MockSerializer* serializers[] = { &emptySerializer, &nullSerializer };
291
292 for (size_t i = 0; i < SK_ARRAY_COUNT(serializers); ++i) {
293 SkDynamicMemoryWStream wstream;
294 REPORTER_ASSERT(reporter, !serializers[i]->didEncode());
295 picture->serialize(&wstream, serializers[i]);
296 REPORTER_ASSERT(reporter, serializers[i]->didEncode());
297
Ben Wagner145dbcd2016-11-03 14:40:50 -0400298 std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
299 sk_sp<SkPicture> deserialized(SkPicture::MakeFromStream(rstream.get()));
fmalitac3470342015-09-04 11:36:39 -0700300 REPORTER_ASSERT(reporter, deserialized);
301 REPORTER_ASSERT(reporter, deserialized->approximateOpCount() > 0);
302 }
303}
304
reed759373a2015-07-03 21:01:10 -0700305DEF_TEST(Image_NewRasterCopy, reporter) {
306 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0);
307 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0);
308 const SkPMColor blue = SkPackARGB32(0xFF, 0, 0, 0xFF);
309 SkPMColor colors[] = { red, green, blue, 0 };
Hal Canary342b7ac2016-11-04 11:49:42 -0400310 sk_sp<SkColorTable> ctable(new SkColorTable(colors, SK_ARRAY_COUNT(colors)));
reed759373a2015-07-03 21:01:10 -0700311 // The colortable made a copy, so we can trash the original colors
312 memset(colors, 0xFF, sizeof(colors));
313
314 const SkImageInfo srcInfo = SkImageInfo::Make(2, 2, kIndex_8_SkColorType, kPremul_SkAlphaType);
315 const size_t srcRowBytes = 2 * sizeof(uint8_t);
316 uint8_t indices[] = { 0, 1, 2, 3 };
Hal Canary342b7ac2016-11-04 11:49:42 -0400317 auto image = SkImage::MakeRasterCopy(SkPixmap(srcInfo, indices, srcRowBytes, ctable.get()));
reed759373a2015-07-03 21:01:10 -0700318 // The image made a copy, so we can trash the original indices
319 memset(indices, 0xFF, sizeof(indices));
320
321 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2);
322 const size_t dstRowBytes = 2 * sizeof(SkPMColor);
323 SkPMColor pixels[4];
324 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect
325 image->readPixels(dstInfo, pixels, dstRowBytes, 0, 0);
326 REPORTER_ASSERT(reporter, red == pixels[0]);
327 REPORTER_ASSERT(reporter, green == pixels[1]);
328 REPORTER_ASSERT(reporter, blue == pixels[2]);
329 REPORTER_ASSERT(reporter, 0 == pixels[3]);
330}
fmalita8c0144c2015-07-22 05:56:16 -0700331
332// Test that a draw that only partially covers the drawing surface isn't
333// interpreted as covering the entire drawing surface (i.e., exercise one of the
334// conditions of SkCanvas::wouldOverwriteEntireSurface()).
335DEF_TEST(Image_RetainSnapshot, reporter) {
336 const SkPMColor red = SkPackARGB32(0xFF, 0xFF, 0, 0);
337 const SkPMColor green = SkPackARGB32(0xFF, 0, 0xFF, 0);
338 SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2);
reede8f30622016-03-23 18:59:25 -0700339 auto surface(SkSurface::MakeRaster(info));
fmalita8c0144c2015-07-22 05:56:16 -0700340 surface->getCanvas()->clear(0xFF00FF00);
341
342 SkPMColor pixels[4];
343 memset(pixels, 0xFF, sizeof(pixels)); // init with values we don't expect
344 const SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(2, 2);
345 const size_t dstRowBytes = 2 * sizeof(SkPMColor);
346
reed9ce9d672016-03-17 10:51:11 -0700347 sk_sp<SkImage> image1(surface->makeImageSnapshot());
fmalita8c0144c2015-07-22 05:56:16 -0700348 REPORTER_ASSERT(reporter, image1->readPixels(dstInfo, pixels, dstRowBytes, 0, 0));
349 for (size_t i = 0; i < SK_ARRAY_COUNT(pixels); ++i) {
350 REPORTER_ASSERT(reporter, pixels[i] == green);
351 }
352
353 SkPaint paint;
reed374772b2016-10-05 17:33:02 -0700354 paint.setBlendMode(SkBlendMode::kSrc);
fmalita8c0144c2015-07-22 05:56:16 -0700355 paint.setColor(SK_ColorRED);
356
357 surface->getCanvas()->drawRect(SkRect::MakeXYWH(1, 1, 1, 1), paint);
358
reed9ce9d672016-03-17 10:51:11 -0700359 sk_sp<SkImage> image2(surface->makeImageSnapshot());
fmalita8c0144c2015-07-22 05:56:16 -0700360 REPORTER_ASSERT(reporter, image2->readPixels(dstInfo, pixels, dstRowBytes, 0, 0));
361 REPORTER_ASSERT(reporter, pixels[0] == green);
362 REPORTER_ASSERT(reporter, pixels[1] == green);
363 REPORTER_ASSERT(reporter, pixels[2] == green);
364 REPORTER_ASSERT(reporter, pixels[3] == red);
365}
reed80c772b2015-07-30 18:58:23 -0700366
367/////////////////////////////////////////////////////////////////////////////////////////////////
reed80c772b2015-07-30 18:58:23 -0700368
369static void make_bitmap_mutable(SkBitmap* bm) {
370 bm->allocN32Pixels(10, 10);
371}
372
373static void make_bitmap_immutable(SkBitmap* bm) {
374 bm->allocN32Pixels(10, 10);
375 bm->setImmutable();
376}
377
378DEF_TEST(image_newfrombitmap, reporter) {
379 const struct {
380 void (*fMakeProc)(SkBitmap*);
381 bool fExpectPeekSuccess;
382 bool fExpectSharedID;
fmalitaddbbdda2015-08-20 08:47:26 -0700383 bool fExpectLazy;
reed80c772b2015-07-30 18:58:23 -0700384 } rec[] = {
fmalitaddbbdda2015-08-20 08:47:26 -0700385 { make_bitmap_mutable, true, false, false },
386 { make_bitmap_immutable, true, true, false },
reed80c772b2015-07-30 18:58:23 -0700387 };
388
389 for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) {
390 SkBitmap bm;
391 rec[i].fMakeProc(&bm);
392
reed9ce9d672016-03-17 10:51:11 -0700393 sk_sp<SkImage> image(SkImage::MakeFromBitmap(bm));
reed80c772b2015-07-30 18:58:23 -0700394 SkPixmap pmap;
395
396 const bool sharedID = (image->uniqueID() == bm.getGenerationID());
397 REPORTER_ASSERT(reporter, sharedID == rec[i].fExpectSharedID);
398
reed80c772b2015-07-30 18:58:23 -0700399 const bool peekSuccess = image->peekPixels(&pmap);
400 REPORTER_ASSERT(reporter, peekSuccess == rec[i].fExpectPeekSuccess);
fmalitaddbbdda2015-08-20 08:47:26 -0700401
402 const bool lazy = image->isLazyGenerated();
403 REPORTER_ASSERT(reporter, lazy == rec[i].fExpectLazy);
reed80c772b2015-07-30 18:58:23 -0700404 }
405}
reed6f1216a2015-08-04 08:10:13 -0700406
407///////////////////////////////////////////////////////////////////////////////////////////////////
408#if SK_SUPPORT_GPU
409
reed6f1216a2015-08-04 08:10:13 -0700410#include "SkBitmapCache.h"
411
412/*
413 * This tests the caching (and preemptive purge) of the raster equivalent of a gpu-image.
414 * We cache it for performance when drawing into a raster surface.
415 *
416 * A cleaner test would know if each drawImage call triggered a read-back from the gpu,
417 * but we don't have that facility (at the moment) so we use a little internal knowledge
418 * of *how* the raster version is cached, and look for that.
419 */
bsalomon68d91342016-04-12 09:59:58 -0700420DEF_GPUTEST_FOR_RENDERING_CONTEXTS(c, reporter, ctxInfo) {
kkinnunen7b94c142015-11-24 07:39:40 -0800421 SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
bsalomon8b7451a2016-05-11 06:33:06 -0700422 sk_sp<SkImage> image(create_gpu_image(ctxInfo.grContext()));
reed6f1216a2015-08-04 08:10:13 -0700423 const uint32_t uniqueID = image->uniqueID();
424
reede8f30622016-03-23 18:59:25 -0700425 auto surface(SkSurface::MakeRaster(info));
reed6f1216a2015-08-04 08:10:13 -0700426
427 // now we can test drawing a gpu-backed image into a cpu-backed surface
428
429 {
430 SkBitmap cachedBitmap;
431 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(uniqueID, &cachedBitmap));
432 }
433
434 surface->getCanvas()->drawImage(image, 0, 0);
435 {
436 SkBitmap cachedBitmap;
437 if (SkBitmapCache::Find(uniqueID, &cachedBitmap)) {
438 REPORTER_ASSERT(reporter, cachedBitmap.getGenerationID() == uniqueID);
439 REPORTER_ASSERT(reporter, cachedBitmap.isImmutable());
440 REPORTER_ASSERT(reporter, cachedBitmap.getPixels());
441 } else {
442 // unexpected, but not really a bug, since the cache is global and this test may be
443 // run w/ other threads competing for its budget.
444 SkDebugf("SkImage_Gpu2Cpu : cachedBitmap was already purged\n");
445 }
446 }
447
448 image.reset(nullptr);
449 {
450 SkBitmap cachedBitmap;
451 REPORTER_ASSERT(reporter, !SkBitmapCache::Find(uniqueID, &cachedBitmap));
452 }
453}
bsalomon8e74f802016-01-30 10:01:40 -0800454
Mike Kleinc168a3a2016-11-14 14:53:13 +0000455DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_newTextureImage, reporter, contextInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700456 GrContext* context = contextInfo.grContext();
bsalomon0fd3c812016-05-11 10:38:05 -0700457 sk_gpu_test::TestContext* testContext = contextInfo.testContext();
bsalomonf2f1c172016-04-05 12:59:06 -0700458
bsalomon8e74f802016-01-30 10:01:40 -0800459 GrContextFactory otherFactory;
bsalomon0fd3c812016-05-11 10:38:05 -0700460 GrContextFactory::ContextType otherContextType =
461 GrContextFactory::NativeContextTypeForBackend(testContext->backend());
462 ContextInfo otherContextInfo = otherFactory.getContextInfo(otherContextType);
463 testContext->makeCurrent();
bsalomon8e74f802016-01-30 10:01:40 -0800464
reed9ce9d672016-03-17 10:51:11 -0700465 std::function<sk_sp<SkImage>()> imageFactories[] = {
bsalomon8e74f802016-01-30 10:01:40 -0800466 create_image,
467 create_codec_image,
468 create_data_image,
469 // Create an image from a picture.
470 create_picture_image,
471 // Create a texture image.
472 [context] { return create_gpu_image(context); },
473 // Create a texture image in a another GrContext.
bsalomon0fd3c812016-05-11 10:38:05 -0700474 [testContext, otherContextInfo] {
475 otherContextInfo.testContext()->makeCurrent();
bsalomon8b7451a2016-05-11 06:33:06 -0700476 sk_sp<SkImage> otherContextImage = create_gpu_image(otherContextInfo.grContext());
bsalomon0fd3c812016-05-11 10:38:05 -0700477 testContext->makeCurrent();
bsalomon8e74f802016-01-30 10:01:40 -0800478 return otherContextImage;
479 }
480 };
481
482 for (auto factory : imageFactories) {
reed9ce9d672016-03-17 10:51:11 -0700483 sk_sp<SkImage> image(factory());
bsalomon8e74f802016-01-30 10:01:40 -0800484 if (!image) {
485 ERRORF(reporter, "Error creating image.");
486 continue;
487 }
488 GrTexture* origTexture = as_IB(image)->peekTexture();
489
reed9ce9d672016-03-17 10:51:11 -0700490 sk_sp<SkImage> texImage(image->makeTextureImage(context));
bsalomon8e74f802016-01-30 10:01:40 -0800491 if (!texImage) {
492 // We execpt to fail if image comes from a different GrContext.
493 if (!origTexture || origTexture->getContext() == context) {
494 ERRORF(reporter, "newTextureImage failed.");
495 }
496 continue;
497 }
498 GrTexture* copyTexture = as_IB(texImage)->peekTexture();
499 if (!copyTexture) {
500 ERRORF(reporter, "newTextureImage returned non-texture image.");
501 continue;
502 }
503 if (origTexture) {
504 if (origTexture != copyTexture) {
505 ERRORF(reporter, "newTextureImage made unnecessary texture copy.");
506 }
507 }
508 if (image->width() != texImage->width() || image->height() != texImage->height()) {
509 ERRORF(reporter, "newTextureImage changed the image size.");
510 }
brianosman69c166d2016-08-17 14:01:05 -0700511 if (image->alphaType() != texImage->alphaType()) {
512 ERRORF(reporter, "newTextureImage changed image alpha type.");
bsalomon8e74f802016-01-30 10:01:40 -0800513 }
514 }
515}
bsalomone5b651f2016-06-15 07:36:15 -0700516
bsalomon634b4302016-07-12 18:11:17 -0700517DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkImage_makeNonTextureImage, reporter, contextInfo) {
518 GrContext* context = contextInfo.grContext();
519
520 std::function<sk_sp<SkImage>()> imageFactories[] = {
521 create_image,
522 create_codec_image,
523 create_data_image,
524 create_picture_image,
525 [context] { return create_gpu_image(context); },
526 };
527 for (auto factory : imageFactories) {
528 sk_sp<SkImage> image = factory();
529 if (!image->isTextureBacked()) {
530 REPORTER_ASSERT(reporter, image->makeNonTextureImage().get() == image.get());
531 if (!(image = image->makeTextureImage(context))) {
532 continue;
533 }
534 }
535 auto rasterImage = image->makeNonTextureImage();
536 if (!rasterImage) {
537 ERRORF(reporter, "makeNonTextureImage failed for texture-backed image.");
538 }
539 REPORTER_ASSERT(reporter, !rasterImage->isTextureBacked());
540 assert_equal(reporter, image.get(), nullptr, rasterImage.get());
541 }
542}
543
bsalomon363bc332016-06-15 14:15:30 -0700544DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SkImage_drawAbandonedGpuImage, reporter, contextInfo) {
bsalomone5b651f2016-06-15 07:36:15 -0700545 auto context = contextInfo.grContext();
546 auto image = create_gpu_image(context);
547 auto info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType);
548 auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info));
549 as_IB(image)->peekTexture()->abandon();
550 surface->getCanvas()->drawImage(image, 0, 0);
551}
552
reed6f1216a2015-08-04 08:10:13 -0700553#endif
halcanaryc56c6ef2015-09-28 11:55:28 -0700554
halcanary6950de62015-11-07 05:29:00 -0800555// https://bug.skia.org/4390
halcanaryc56c6ef2015-09-28 11:55:28 -0700556DEF_TEST(ImageFromIndex8Bitmap, r) {
557 SkPMColor pmColors[1] = {SkPreMultiplyColor(SK_ColorWHITE)};
558 SkBitmap bm;
Hal Canary342b7ac2016-11-04 11:49:42 -0400559 sk_sp<SkColorTable> ctable( new SkColorTable(pmColors, SK_ARRAY_COUNT(pmColors)));
560 SkImageInfo info = SkImageInfo::Make(1, 1, kIndex_8_SkColorType, kPremul_SkAlphaType);
561 bm.allocPixels(info, nullptr, ctable.get());
halcanaryc56c6ef2015-09-28 11:55:28 -0700562 SkAutoLockPixels autoLockPixels(bm);
563 *bm.getAddr8(0, 0) = 0;
reed9ce9d672016-03-17 10:51:11 -0700564 sk_sp<SkImage> img(SkImage::MakeFromBitmap(bm));
565 REPORTER_ASSERT(r, img != nullptr);
halcanaryc56c6ef2015-09-28 11:55:28 -0700566}
kkinnunen4e184132015-11-17 22:53:28 -0800567
kkinnunen4e184132015-11-17 22:53:28 -0800568class EmptyGenerator : public SkImageGenerator {
569public:
570 EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {}
571};
572
kkinnunen7b94c142015-11-24 07:39:40 -0800573DEF_TEST(ImageEmpty, reporter) {
kkinnunen4e184132015-11-17 22:53:28 -0800574 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
reed9ce9d672016-03-17 10:51:11 -0700575 SkPixmap pmap(info, nullptr, 0);
576 REPORTER_ASSERT(reporter, nullptr == SkImage::MakeRasterCopy(pmap));
577 REPORTER_ASSERT(reporter, nullptr == SkImage::MakeRasterData(info, nullptr, 0));
578 REPORTER_ASSERT(reporter, nullptr == SkImage::MakeFromRaster(pmap, nullptr, nullptr));
579 REPORTER_ASSERT(reporter, nullptr == SkImage::MakeFromGenerator(new EmptyGenerator));
kkinnunen4e184132015-11-17 22:53:28 -0800580}
581
kkinnunen7b94c142015-11-24 07:39:40 -0800582DEF_TEST(ImageDataRef, reporter) {
kkinnunen4e184132015-11-17 22:53:28 -0800583 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
584 size_t rowBytes = info.minRowBytes();
585 size_t size = info.getSafeSize(rowBytes);
reed9ce9d672016-03-17 10:51:11 -0700586 sk_sp<SkData> data = SkData::MakeUninitialized(size);
kkinnunen4e184132015-11-17 22:53:28 -0800587 REPORTER_ASSERT(reporter, data->unique());
reed9ce9d672016-03-17 10:51:11 -0700588 sk_sp<SkImage> image = SkImage::MakeRasterData(info, data, rowBytes);
kkinnunen4e184132015-11-17 22:53:28 -0800589 REPORTER_ASSERT(reporter, !data->unique());
reed9ce9d672016-03-17 10:51:11 -0700590 image.reset();
kkinnunen4e184132015-11-17 22:53:28 -0800591 REPORTER_ASSERT(reporter, data->unique());
kkinnunen4e184132015-11-17 22:53:28 -0800592}
593
kkinnunen4e184132015-11-17 22:53:28 -0800594static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) {
595 for (int i = 0; i < count; ++i) {
596 if (pixels[i] != expected) {
597 return false;
598 }
599 }
600 return true;
601}
602
kkinnunen7b94c142015-11-24 07:39:40 -0800603static void test_read_pixels(skiatest::Reporter* reporter, SkImage* image) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700604 if (!image) {
605 ERRORF(reporter, "Failed to create image!");
606 return;
607 }
kkinnunen7b94c142015-11-24 07:39:40 -0800608 const SkPMColor expected = SkPreMultiplyColor(SK_ColorWHITE);
kkinnunen4e184132015-11-17 22:53:28 -0800609 const SkPMColor notExpected = ~expected;
610
611 const int w = 2, h = 2;
612 const size_t rowBytes = w * sizeof(SkPMColor);
613 SkPMColor pixels[w*h];
614
615 SkImageInfo info;
616
617 info = SkImageInfo::MakeUnknown(w, h);
618 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0));
619
620 // out-of-bounds should fail
621 info = SkImageInfo::MakeN32Premul(w, h);
622 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0));
623 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h));
624 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0));
625 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height()));
626
627 // top-left should succeed
kkinnunen7b94c142015-11-24 07:39:40 -0800628 sk_memset32(pixels, notExpected, w*h);
kkinnunen4e184132015-11-17 22:53:28 -0800629 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0));
630 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
631
632 // bottom-right should succeed
kkinnunen7b94c142015-11-24 07:39:40 -0800633 sk_memset32(pixels, notExpected, w*h);
kkinnunen4e184132015-11-17 22:53:28 -0800634 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
635 image->width() - w, image->height() - h));
636 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
637
638 // partial top-left should succeed
kkinnunen7b94c142015-11-24 07:39:40 -0800639 sk_memset32(pixels, notExpected, w*h);
kkinnunen4e184132015-11-17 22:53:28 -0800640 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1));
641 REPORTER_ASSERT(reporter, pixels[3] == expected);
642 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected));
643
644 // partial bottom-right should succeed
kkinnunen7b94c142015-11-24 07:39:40 -0800645 sk_memset32(pixels, notExpected, w*h);
kkinnunen4e184132015-11-17 22:53:28 -0800646 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
647 image->width() - 1, image->height() - 1));
648 REPORTER_ASSERT(reporter, pixels[0] == expected);
649 REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected));
650}
kkinnunen7b94c142015-11-24 07:39:40 -0800651DEF_TEST(ImageReadPixels, reporter) {
reed9ce9d672016-03-17 10:51:11 -0700652 sk_sp<SkImage> image(create_image());
653 test_read_pixels(reporter, image.get());
kkinnunen7b94c142015-11-24 07:39:40 -0800654
reed9ce9d672016-03-17 10:51:11 -0700655 image = create_data_image();
656 test_read_pixels(reporter, image.get());
kkinnunen7b94c142015-11-24 07:39:40 -0800657
658 RasterDataHolder dataHolder;
reed9ce9d672016-03-17 10:51:11 -0700659 image = create_rasterproc_image(&dataHolder);
660 test_read_pixels(reporter, image.get());
kkinnunen7b94c142015-11-24 07:39:40 -0800661 image.reset();
662 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount);
663
reed9ce9d672016-03-17 10:51:11 -0700664 image = create_codec_image();
665 test_read_pixels(reporter, image.get());
kkinnunen7b94c142015-11-24 07:39:40 -0800666}
667#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700668DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageReadPixels_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700669 test_read_pixels(reporter, create_gpu_image(ctxInfo.grContext()).get());
kkinnunen7b94c142015-11-24 07:39:40 -0800670}
671#endif
kkinnunen4e184132015-11-17 22:53:28 -0800672
673static void check_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image,
674 const SkBitmap& bitmap, SkImage::LegacyBitmapMode mode) {
675 REPORTER_ASSERT(reporter, image->width() == bitmap.width());
676 REPORTER_ASSERT(reporter, image->height() == bitmap.height());
brianosman69c166d2016-08-17 14:01:05 -0700677 REPORTER_ASSERT(reporter, image->alphaType() == bitmap.alphaType());
kkinnunen4e184132015-11-17 22:53:28 -0800678
679 if (SkImage::kRO_LegacyBitmapMode == mode) {
680 REPORTER_ASSERT(reporter, bitmap.isImmutable());
681 }
682
683 SkAutoLockPixels alp(bitmap);
684 REPORTER_ASSERT(reporter, bitmap.getPixels());
685
686 const SkImageInfo info = SkImageInfo::MakeN32(1, 1, bitmap.alphaType());
687 SkPMColor imageColor;
688 REPORTER_ASSERT(reporter, image->readPixels(info, &imageColor, sizeof(SkPMColor), 0, 0));
689 REPORTER_ASSERT(reporter, imageColor == *bitmap.getAddr32(0, 0));
690}
691
kkinnunen7b94c142015-11-24 07:39:40 -0800692static void test_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image, SkImage::LegacyBitmapMode mode) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700693 if (!image) {
694 ERRORF(reporter, "Failed to create image.");
695 return;
696 }
kkinnunen7b94c142015-11-24 07:39:40 -0800697 SkBitmap bitmap;
698 REPORTER_ASSERT(reporter, image->asLegacyBitmap(&bitmap, mode));
699 check_legacy_bitmap(reporter, image, bitmap, mode);
700
701 // Test subsetting to exercise the rowBytes logic.
702 SkBitmap tmp;
703 REPORTER_ASSERT(reporter, bitmap.extractSubset(&tmp, SkIRect::MakeWH(image->width() / 2,
704 image->height() / 2)));
reed9ce9d672016-03-17 10:51:11 -0700705 sk_sp<SkImage> subsetImage(SkImage::MakeFromBitmap(tmp));
706 REPORTER_ASSERT(reporter, subsetImage.get());
kkinnunen7b94c142015-11-24 07:39:40 -0800707
708 SkBitmap subsetBitmap;
709 REPORTER_ASSERT(reporter, subsetImage->asLegacyBitmap(&subsetBitmap, mode));
reed9ce9d672016-03-17 10:51:11 -0700710 check_legacy_bitmap(reporter, subsetImage.get(), subsetBitmap, mode);
kkinnunen7b94c142015-11-24 07:39:40 -0800711}
712DEF_TEST(ImageLegacyBitmap, reporter) {
kkinnunen4e184132015-11-17 22:53:28 -0800713 const SkImage::LegacyBitmapMode modes[] = {
714 SkImage::kRO_LegacyBitmapMode,
715 SkImage::kRW_LegacyBitmapMode,
716 };
kkinnunen7b94c142015-11-24 07:39:40 -0800717 for (auto& mode : modes) {
reed9ce9d672016-03-17 10:51:11 -0700718 sk_sp<SkImage> image(create_image());
719 test_legacy_bitmap(reporter, image.get(), mode);
kkinnunen4e184132015-11-17 22:53:28 -0800720
reed9ce9d672016-03-17 10:51:11 -0700721 image = create_data_image();
722 test_legacy_bitmap(reporter, image.get(), mode);
kkinnunen4e184132015-11-17 22:53:28 -0800723
kkinnunen7b94c142015-11-24 07:39:40 -0800724 RasterDataHolder dataHolder;
reed9ce9d672016-03-17 10:51:11 -0700725 image = create_rasterproc_image(&dataHolder);
726 test_legacy_bitmap(reporter, image.get(), mode);
kkinnunen7b94c142015-11-24 07:39:40 -0800727 image.reset();
728 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount);
729
reed9ce9d672016-03-17 10:51:11 -0700730 image = create_codec_image();
731 test_legacy_bitmap(reporter, image.get(), mode);
kkinnunen4e184132015-11-17 22:53:28 -0800732 }
733}
kkinnunen4e184132015-11-17 22:53:28 -0800734#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700735DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageLegacyBitmap_Gpu, reporter, ctxInfo) {
kkinnunen7b94c142015-11-24 07:39:40 -0800736 const SkImage::LegacyBitmapMode modes[] = {
737 SkImage::kRO_LegacyBitmapMode,
738 SkImage::kRW_LegacyBitmapMode,
739 };
740 for (auto& mode : modes) {
bsalomon8b7451a2016-05-11 06:33:06 -0700741 sk_sp<SkImage> image(create_gpu_image(ctxInfo.grContext()));
reed9ce9d672016-03-17 10:51:11 -0700742 test_legacy_bitmap(reporter, image.get(), mode);
kkinnunen4e184132015-11-17 22:53:28 -0800743 }
kkinnunen7b94c142015-11-24 07:39:40 -0800744}
kkinnunen4e184132015-11-17 22:53:28 -0800745#endif
746
kkinnunen7b94c142015-11-24 07:39:40 -0800747static void test_peek(skiatest::Reporter* reporter, SkImage* image, bool expectPeekSuccess) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700748 if (!image) {
749 ERRORF(reporter, "Failed to create image!");
750 return;
751 }
reed6ceeebd2016-03-09 14:26:26 -0800752 SkPixmap pm;
753 bool success = image->peekPixels(&pm);
kkinnunen7b94c142015-11-24 07:39:40 -0800754 REPORTER_ASSERT(reporter, expectPeekSuccess == success);
755 if (success) {
reed6ceeebd2016-03-09 14:26:26 -0800756 const SkImageInfo& info = pm.info();
kkinnunen7b94c142015-11-24 07:39:40 -0800757 REPORTER_ASSERT(reporter, 20 == info.width());
758 REPORTER_ASSERT(reporter, 20 == info.height());
759 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType());
760 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() ||
761 kOpaque_SkAlphaType == info.alphaType());
reed6ceeebd2016-03-09 14:26:26 -0800762 REPORTER_ASSERT(reporter, info.minRowBytes() <= pm.rowBytes());
763 REPORTER_ASSERT(reporter, SkPreMultiplyColor(SK_ColorWHITE) == *pm.addr32(0, 0));
kkinnunen4e184132015-11-17 22:53:28 -0800764 }
kkinnunen7b94c142015-11-24 07:39:40 -0800765}
766DEF_TEST(ImagePeek, reporter) {
reed9ce9d672016-03-17 10:51:11 -0700767 sk_sp<SkImage> image(create_image());
768 test_peek(reporter, image.get(), true);
kkinnunen7b94c142015-11-24 07:39:40 -0800769
reed9ce9d672016-03-17 10:51:11 -0700770 image = create_data_image();
771 test_peek(reporter, image.get(), true);
kkinnunen7b94c142015-11-24 07:39:40 -0800772
773 RasterDataHolder dataHolder;
reed9ce9d672016-03-17 10:51:11 -0700774 image = create_rasterproc_image(&dataHolder);
775 test_peek(reporter, image.get(), true);
kkinnunen7b94c142015-11-24 07:39:40 -0800776 image.reset();
777 REPORTER_ASSERT(reporter, 1 == dataHolder.fReleaseCount);
778
reed9ce9d672016-03-17 10:51:11 -0700779 image = create_codec_image();
780 test_peek(reporter, image.get(), false);
kkinnunen4e184132015-11-17 22:53:28 -0800781}
782#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700783DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImagePeek_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700784 sk_sp<SkImage> image(create_gpu_image(ctxInfo.grContext()));
reed9ce9d672016-03-17 10:51:11 -0700785 test_peek(reporter, image.get(), false);
kkinnunen7b94c142015-11-24 07:39:40 -0800786}
787#endif
kkinnunen4e184132015-11-17 22:53:28 -0800788
kkinnunen7b94c142015-11-24 07:39:40 -0800789#if SK_SUPPORT_GPU
790struct TextureReleaseChecker {
791 TextureReleaseChecker() : fReleaseCount(0) {}
792 int fReleaseCount;
793 static void Release(void* self) {
794 static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
kkinnunen4e184132015-11-17 22:53:28 -0800795 }
796};
brianosmandb2cb102016-07-22 07:22:04 -0700797DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SkImage_NewFromTextureRelease, reporter, ctxInfo) {
798 const int kWidth = 10;
799 const int kHeight = 10;
Ben Wagner7ecc5962016-11-02 17:07:33 -0400800 std::unique_ptr<uint32_t[]> pixels(new uint32_t[kWidth * kHeight]);
kkinnunen7b94c142015-11-24 07:39:40 -0800801 GrBackendTextureDesc backendDesc;
brianosmandb2cb102016-07-22 07:22:04 -0700802 backendDesc.fConfig = kRGBA_8888_GrPixelConfig;
kkinnunen7b94c142015-11-24 07:39:40 -0800803 backendDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
brianosmandb2cb102016-07-22 07:22:04 -0700804 backendDesc.fWidth = kWidth;
805 backendDesc.fHeight = kHeight;
kkinnunen7b94c142015-11-24 07:39:40 -0800806 backendDesc.fSampleCnt = 0;
brianosmandb2cb102016-07-22 07:22:04 -0700807 backendDesc.fTextureHandle = ctxInfo.grContext()->getGpu()->createTestingOnlyBackendTexture(
808 pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true);
809
kkinnunen7b94c142015-11-24 07:39:40 -0800810 TextureReleaseChecker releaseChecker;
reed9ce9d672016-03-17 10:51:11 -0700811 sk_sp<SkImage> refImg(
bsalomon8b7451a2016-05-11 06:33:06 -0700812 SkImage::MakeFromTexture(ctxInfo.grContext(), backendDesc, kPremul_SkAlphaType,
reed9ce9d672016-03-17 10:51:11 -0700813 TextureReleaseChecker::Release, &releaseChecker));
kkinnunen4e184132015-11-17 22:53:28 -0800814
kkinnunen4e184132015-11-17 22:53:28 -0800815 // Now exercise the release proc
kkinnunen7b94c142015-11-24 07:39:40 -0800816 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
kkinnunen4e184132015-11-17 22:53:28 -0800817 refImg.reset(nullptr); // force a release of the image
kkinnunen7b94c142015-11-24 07:39:40 -0800818 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
brianosmandb2cb102016-07-22 07:22:04 -0700819
820 ctxInfo.grContext()->getGpu()->deleteTestingOnlyBackendTexture(backendDesc.fTextureHandle);
kkinnunen4e184132015-11-17 22:53:28 -0800821}
bsalomon0d996862016-03-09 18:44:43 -0800822
823static void check_images_same(skiatest::Reporter* reporter, const SkImage* a, const SkImage* b) {
824 if (a->width() != b->width() || a->height() != b->height()) {
825 ERRORF(reporter, "Images must have the same size");
826 return;
827 }
brianosman69c166d2016-08-17 14:01:05 -0700828 if (a->alphaType() != b->alphaType()) {
829 ERRORF(reporter, "Images must have the same alpha type");
bsalomon0d996862016-03-09 18:44:43 -0800830 return;
831 }
832
833 SkImageInfo info = SkImageInfo::MakeN32Premul(a->width(), a->height());
834 SkAutoPixmapStorage apm;
835 SkAutoPixmapStorage bpm;
836
837 apm.alloc(info);
838 bpm.alloc(info);
839
840 if (!a->readPixels(apm, 0, 0)) {
841 ERRORF(reporter, "Could not read image a's pixels");
842 return;
843 }
844 if (!b->readPixels(bpm, 0, 0)) {
845 ERRORF(reporter, "Could not read image b's pixels");
846 return;
847 }
848
849 for (auto y = 0; y < info.height(); ++y) {
850 for (auto x = 0; x < info.width(); ++x) {
851 uint32_t pixelA = *apm.addr32(x, y);
852 uint32_t pixelB = *bpm.addr32(x, y);
853 if (pixelA != pixelB) {
854 ERRORF(reporter, "Expected image pixels to be the same. At %d,%d 0x%08x != 0x%08x",
855 x, y, pixelA, pixelB);
856 return;
857 }
858 }
859 }
860}
861
egdanielab527a52016-06-28 08:07:26 -0700862DEF_GPUTEST_FOR_RENDERING_CONTEXTS(NewTextureFromPixmap, reporter, ctxInfo) {
bsalomone6d665e2016-03-10 07:22:25 -0800863 for (auto create : {&create_image,
864 &create_image_565,
865 &create_image_ct}) {
reed9ce9d672016-03-17 10:51:11 -0700866 sk_sp<SkImage> image((*create)());
bsalomon0d996862016-03-09 18:44:43 -0800867 if (!image) {
868 ERRORF(reporter, "Could not create image");
869 return;
870 }
871
872 SkPixmap pixmap;
873 if (!image->peekPixels(&pixmap)) {
874 ERRORF(reporter, "peek failed");
875 } else {
bsalomon8b7451a2016-05-11 06:33:06 -0700876 sk_sp<SkImage> texImage(SkImage::MakeTextureFromPixmap(ctxInfo.grContext(), pixmap,
reed9ce9d672016-03-17 10:51:11 -0700877 SkBudgeted::kNo));
bsalomon0d996862016-03-09 18:44:43 -0800878 if (!texImage) {
879 ERRORF(reporter, "NewTextureFromPixmap failed.");
880 } else {
reed9ce9d672016-03-17 10:51:11 -0700881 check_images_same(reporter, image.get(), texImage.get());
bsalomon0d996862016-03-09 18:44:43 -0800882 }
883 }
884 }
885}
886
Mike Kleinc168a3a2016-11-14 14:53:13 +0000887DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredTextureImage, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700888 GrContext* context = ctxInfo.grContext();
bsalomon0fd3c812016-05-11 10:38:05 -0700889 sk_gpu_test::TestContext* testContext = ctxInfo.testContext();
bungeman6bd52842016-10-27 09:30:08 -0700890 sk_sp<GrContextThreadSafeProxy> proxy = context->threadSafeProxy();
bsalomon41b952c2016-03-11 06:46:33 -0800891
892 GrContextFactory otherFactory;
bsalomonf2f1c172016-04-05 12:59:06 -0700893 ContextInfo otherContextInfo =
bsalomon85b4b532016-04-05 11:06:27 -0700894 otherFactory.getContextInfo(GrContextFactory::kNativeGL_ContextType);
bsalomon41b952c2016-03-11 06:46:33 -0800895
bsalomon0fd3c812016-05-11 10:38:05 -0700896 testContext->makeCurrent();
bsalomon41b952c2016-03-11 06:46:33 -0800897 REPORTER_ASSERT(reporter, proxy);
898 struct {
ericrkb4da01d2016-06-13 11:18:14 -0700899 std::function<sk_sp<SkImage> ()> fImageFactory;
900 std::vector<SkImage::DeferredTextureImageUsageParams> fParams;
901 SkFilterQuality fExpectedQuality;
902 int fExpectedScaleFactor;
903 bool fExpectation;
bsalomon41b952c2016-03-11 06:46:33 -0800904 } testCases[] = {
cblume33e0cb52016-08-30 12:09:23 -0700905 { create_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
906 kNone_SkFilterQuality, 1, true },
907 { create_codec_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
908 kNone_SkFilterQuality, 1, true },
909 { create_data_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
910 kNone_SkFilterQuality, 1, true },
911 { create_picture_image, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
912 kNone_SkFilterQuality, 1, false },
913 { [context] { return create_gpu_image(context); },
914 {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
915 kNone_SkFilterQuality, 1, false },
bsalomon41b952c2016-03-11 06:46:33 -0800916 // Create a texture image in a another GrContext.
bsalomon0fd3c812016-05-11 10:38:05 -0700917 { [testContext, otherContextInfo] {
918 otherContextInfo.testContext()->makeCurrent();
bsalomon8b7451a2016-05-11 06:33:06 -0700919 sk_sp<SkImage> otherContextImage = create_gpu_image(otherContextInfo.grContext());
bsalomon0fd3c812016-05-11 10:38:05 -0700920 testContext->makeCurrent();
bsalomon41b952c2016-03-11 06:46:33 -0800921 return otherContextImage;
cblume33e0cb52016-08-30 12:09:23 -0700922 }, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
923 kNone_SkFilterQuality, 1, false },
ericrkb4da01d2016-06-13 11:18:14 -0700924 // Create an image that is too large to upload.
cblume33e0cb52016-08-30 12:09:23 -0700925 { create_image_large, {{SkMatrix::I(), kNone_SkFilterQuality, 0}},
926 kNone_SkFilterQuality, 1, false },
ericrkb4da01d2016-06-13 11:18:14 -0700927 // Create an image that is too large, but is scaled to an acceptable size.
928 { create_image_large, {{SkMatrix::I(), kMedium_SkFilterQuality, 4}},
929 kMedium_SkFilterQuality, 16, true},
930 // Create an image with multiple low filter qualities, make sure we round up.
931 { create_image_large, {{SkMatrix::I(), kNone_SkFilterQuality, 4},
932 {SkMatrix::I(), kMedium_SkFilterQuality, 4}},
933 kMedium_SkFilterQuality, 16, true},
934 // Create an image with multiple prescale levels, make sure we chose the minimum scale.
935 { create_image_large, {{SkMatrix::I(), kMedium_SkFilterQuality, 5},
936 {SkMatrix::I(), kMedium_SkFilterQuality, 4}},
937 kMedium_SkFilterQuality, 16, true},
bsalomon41b952c2016-03-11 06:46:33 -0800938 };
939
940
941 for (auto testCase : testCases) {
reed9ce9d672016-03-17 10:51:11 -0700942 sk_sp<SkImage> image(testCase.fImageFactory());
scroggo8e6c7ad2016-09-16 08:20:38 -0700943 if (!image) {
944 ERRORF(reporter, "Failed to create image!");
945 continue;
946 }
947
ericrkb4da01d2016-06-13 11:18:14 -0700948 size_t size = image->getDeferredTextureImageData(*proxy, testCase.fParams.data(),
949 static_cast<int>(testCase.fParams.size()),
Brian Osman6c15cc72016-10-17 09:51:37 -0400950 nullptr, nullptr);
bsalomon41b952c2016-03-11 06:46:33 -0800951 static const char *const kFS[] = { "fail", "succeed" };
952 if (SkToBool(size) != testCase.fExpectation) {
953 ERRORF(reporter, "This image was expected to %s but did not.",
954 kFS[testCase.fExpectation]);
955 }
956 if (size) {
957 void* buffer = sk_malloc_throw(size);
958 void* misaligned = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(buffer) + 3);
ericrkb4da01d2016-06-13 11:18:14 -0700959 if (image->getDeferredTextureImageData(*proxy, testCase.fParams.data(),
960 static_cast<int>(testCase.fParams.size()),
Brian Osman6c15cc72016-10-17 09:51:37 -0400961 misaligned, nullptr)) {
bsalomon41b952c2016-03-11 06:46:33 -0800962 ERRORF(reporter, "Should fail when buffer is misaligned.");
963 }
ericrkb4da01d2016-06-13 11:18:14 -0700964 if (!image->getDeferredTextureImageData(*proxy, testCase.fParams.data(),
965 static_cast<int>(testCase.fParams.size()),
Brian Osman6c15cc72016-10-17 09:51:37 -0400966 buffer, nullptr)) {
bsalomon41b952c2016-03-11 06:46:33 -0800967 ERRORF(reporter, "deferred image size succeeded but creation failed.");
968 } else {
969 for (auto budgeted : { SkBudgeted::kNo, SkBudgeted::kYes }) {
reed9ce9d672016-03-17 10:51:11 -0700970 sk_sp<SkImage> newImage(
971 SkImage::MakeFromDeferredTextureImageData(context, buffer, budgeted));
mtklein5f939ab2016-03-16 10:28:35 -0700972 REPORTER_ASSERT(reporter, newImage != nullptr);
bsalomon41b952c2016-03-11 06:46:33 -0800973 if (newImage) {
ericrkb4da01d2016-06-13 11:18:14 -0700974 // Scale the image in software for comparison.
975 SkImageInfo scaled_info = SkImageInfo::MakeN32(
brianosman69c166d2016-08-17 14:01:05 -0700976 image->width() / testCase.fExpectedScaleFactor,
977 image->height() / testCase.fExpectedScaleFactor,
978 image->alphaType());
ericrkb4da01d2016-06-13 11:18:14 -0700979 SkAutoPixmapStorage scaled;
980 scaled.alloc(scaled_info);
981 image->scalePixels(scaled, testCase.fExpectedQuality);
982 sk_sp<SkImage> scaledImage = SkImage::MakeRasterCopy(scaled);
983 check_images_same(reporter, scaledImage.get(), newImage.get());
bsalomon41b952c2016-03-11 06:46:33 -0800984 }
985 // The other context should not be able to create images from texture data
986 // created by the original context.
reed9ce9d672016-03-17 10:51:11 -0700987 sk_sp<SkImage> newImage2(SkImage::MakeFromDeferredTextureImageData(
bsalomon8b7451a2016-05-11 06:33:06 -0700988 otherContextInfo.grContext(), buffer, budgeted));
bsalomon41b952c2016-03-11 06:46:33 -0800989 REPORTER_ASSERT(reporter, !newImage2);
bsalomon0fd3c812016-05-11 10:38:05 -0700990 testContext->makeCurrent();
bsalomon41b952c2016-03-11 06:46:33 -0800991 }
992 }
993 sk_free(buffer);
994 }
995 }
996}
kkinnunen4e184132015-11-17 22:53:28 -0800997#endif
reedeb560282016-07-26 19:42:04 -0700998
999///////////////////////////////////////////////////////////////////////////////////////////////////
1000
1001static void make_all_premul(SkBitmap* bm) {
1002 bm->allocPixels(SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType));
1003 for (int a = 0; a < 256; ++a) {
1004 for (int r = 0; r < 256; ++r) {
1005 // make all valid premul combinations
1006 int c = SkTMin(a, r);
1007 *bm->getAddr32(a, r) = SkPackARGB32(a, c, c, c);
1008 }
1009 }
1010}
1011
1012static bool equal(const SkBitmap& a, const SkBitmap& b) {
1013 SkASSERT(a.width() == b.width());
1014 SkASSERT(a.height() == b.height());
1015 for (int y = 0; y < a.height(); ++y) {
1016 if (0 != memcmp(a.getAddr32(0, y), b.getAddr32(0, y), a.width() * sizeof(SkPMColor))) {
1017 return false;
1018 }
1019 }
1020 return true;
1021}
1022
1023DEF_TEST(image_roundtrip_encode, reporter) {
1024 SkBitmap bm0;
1025 make_all_premul(&bm0);
1026
1027 auto img0 = SkImage::MakeFromBitmap(bm0);
Leon Scroggins294c1c42016-11-08 14:29:46 +00001028 sk_sp<SkData> data(img0->encode(SkImageEncoder::kPNG_Type, 100));
reedeb560282016-07-26 19:42:04 -07001029 auto img1 = SkImage::MakeFromEncoded(data);
mtklein2f3416d2016-08-02 16:02:05 -07001030
reedeb560282016-07-26 19:42:04 -07001031 SkBitmap bm1;
1032 bm1.allocPixels(SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType));
1033 img1->readPixels(bm1.info(), bm1.getPixels(), bm1.rowBytes(), 0, 0);
mtklein2f3416d2016-08-02 16:02:05 -07001034
reedeb560282016-07-26 19:42:04 -07001035 REPORTER_ASSERT(reporter, equal(bm0, bm1));
1036}
1037
1038DEF_TEST(image_roundtrip_premul, reporter) {
1039 SkBitmap bm0;
1040 make_all_premul(&bm0);
1041
1042 SkBitmap bm1;
1043 bm1.allocPixels(SkImageInfo::MakeN32(256, 256, kUnpremul_SkAlphaType));
1044 bm0.readPixels(bm1.info(), bm1.getPixels(), bm1.rowBytes(), 0, 0);
1045
1046 SkBitmap bm2;
1047 bm2.allocPixels(SkImageInfo::MakeN32(256, 256, kPremul_SkAlphaType));
1048 bm1.readPixels(bm2.info(), bm2.getPixels(), bm2.rowBytes(), 0, 0);
1049
1050 REPORTER_ASSERT(reporter, equal(bm0, bm2));
1051}