blob: b1e233fa3afb3a5af929620544d9066977ff6627 [file] [log] [blame]
junov@chromium.org995beb62013-03-28 13:49:22 +00001/*
2 * Copyright 2013 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 */
tfarina@chromium.org4ee16bf2014-01-10 22:08:27 +00007
junov@chromium.org995beb62013-03-28 13:49:22 +00008#include "SkCanvas.h"
reed@google.com4f7c6152014-02-06 14:11:56 +00009#include "SkData.h"
reed41e010c2015-06-09 12:16:53 -070010#include "SkDevice.h"
reed@google.com4f7c6152014-02-06 14:11:56 +000011#include "SkImageEncoder.h"
bsalomon55812362015-06-10 08:49:28 -070012#include "SkImage_Base.h"
junov@chromium.org995beb62013-03-28 13:49:22 +000013#include "SkRRect.h"
14#include "SkSurface.h"
reed@google.com4f7c6152014-02-06 14:11:56 +000015#include "SkUtils.h"
junov@chromium.org995beb62013-03-28 13:49:22 +000016#include "Test.h"
17
18#if SK_SUPPORT_GPU
19#include "GrContextFactory.h"
bsalomon7a617932015-06-16 08:07:16 -070020#include "GrTest.h"
junov@chromium.org995beb62013-03-28 13:49:22 +000021#else
22class GrContextFactory;
23class GrContext;
24#endif
25
26enum SurfaceType {
27 kRaster_SurfaceType,
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000028 kRasterDirect_SurfaceType,
junov@chromium.org995beb62013-03-28 13:49:22 +000029 kGpu_SurfaceType,
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +000030 kGpuScratch_SurfaceType,
bsalomon74f681d2015-06-23 14:38:48 -070031
32 kLastSurfaceType = kGpuScratch_SurfaceType
junov@chromium.org995beb62013-03-28 13:49:22 +000033};
bsalomon74f681d2015-06-23 14:38:48 -070034static const int kSurfaceTypeCnt = kLastSurfaceType + 1;
junov@chromium.org995beb62013-03-28 13:49:22 +000035
reed982542d2014-06-27 06:48:14 -070036static void release_storage(void* pixels, void* context) {
37 SkASSERT(pixels == context);
38 sk_free(pixels);
39}
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000040
bsalomon74f681d2015-06-23 14:38:48 -070041static SkSurface* create_surface(SurfaceType surfaceType, GrContext* context,
42 SkAlphaType at = kPremul_SkAlphaType,
43 SkImageInfo* requestedInfo = NULL) {
44 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000045
46 if (requestedInfo) {
47 *requestedInfo = info;
48 }
junov@chromium.org995beb62013-03-28 13:49:22 +000049
50 switch (surfaceType) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000051 case kRaster_SurfaceType:
52 return SkSurface::NewRaster(info);
reed982542d2014-06-27 06:48:14 -070053 case kRasterDirect_SurfaceType: {
54 const size_t rowBytes = info.minRowBytes();
55 void* storage = sk_malloc_throw(info.getSafeSize(rowBytes));
56 return SkSurface::NewRasterDirectReleaseProc(info, storage, rowBytes,
57 release_storage, storage);
58 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000059 case kGpu_SurfaceType:
bsalomonafe30052015-01-16 07:32:33 -080060 return SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0, NULL);
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +000061 case kGpuScratch_SurfaceType:
bsalomonafe30052015-01-16 07:32:33 -080062 return SkSurface::NewRenderTarget(context, SkSurface::kYes_Budgeted, info, 0, NULL);
junov@chromium.org995beb62013-03-28 13:49:22 +000063 }
junov@chromium.org995beb62013-03-28 13:49:22 +000064 return NULL;
65}
66
reed@google.com4f7c6152014-02-06 14:11:56 +000067enum ImageType {
68 kRasterCopy_ImageType,
69 kRasterData_ImageType,
reedde499882015-06-18 13:41:40 -070070 kRasterProc_ImageType,
reed@google.com4f7c6152014-02-06 14:11:56 +000071 kGpu_ImageType,
reed@google.com4f7c6152014-02-06 14:11:56 +000072 kCodec_ImageType,
73};
reed@google.com999da9c2014-02-06 13:43:07 +000074
reedb2497c22014-12-31 12:31:43 -080075#include "SkImageGenerator.h"
76
77class EmptyGenerator : public SkImageGenerator {
reed3ef71e32015-03-19 08:31:14 -070078public:
79 EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {}
reedb2497c22014-12-31 12:31:43 -080080};
81
82static void test_empty_image(skiatest::Reporter* reporter) {
83 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
84
85 REPORTER_ASSERT(reporter, NULL == SkImage::NewRasterCopy(info, NULL, 0));
86 REPORTER_ASSERT(reporter, NULL == SkImage::NewRasterData(info, NULL, 0));
reedde499882015-06-18 13:41:40 -070087 REPORTER_ASSERT(reporter, NULL == SkImage::NewFromRaster(info, NULL, 0, NULL, NULL));
reedb2497c22014-12-31 12:31:43 -080088 REPORTER_ASSERT(reporter, NULL == SkImage::NewFromGenerator(SkNEW(EmptyGenerator)));
89}
90
91static void test_empty_surface(skiatest::Reporter* reporter, GrContext* ctx) {
92 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
93
94 REPORTER_ASSERT(reporter, NULL == SkSurface::NewRaster(info));
95 REPORTER_ASSERT(reporter, NULL == SkSurface::NewRasterDirect(info, NULL, 0));
96 if (ctx) {
bsalomonafe30052015-01-16 07:32:33 -080097 REPORTER_ASSERT(reporter, NULL ==
98 SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info, 0, NULL));
reedb2497c22014-12-31 12:31:43 -080099 }
100}
101
bsalomone4579ad2015-04-08 08:38:40 -0700102#if SK_SUPPORT_GPU
joshualitt81793412015-07-08 12:54:04 -0700103static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext* ctx) {
bsalomone4579ad2015-04-08 08:38:40 -0700104 if (NULL == ctx) {
105 return;
106 }
bsalomone4579ad2015-04-08 08:38:40 -0700107
jvanverth672bb7f2015-07-13 07:19:57 -0700108 const GrGpu* gpu = ctx->getGpu();
109 if (!gpu) {
bsalomone4579ad2015-04-08 08:38:40 -0700110 return;
111 }
bsalomon7a617932015-06-16 08:07:16 -0700112
jvanverth672bb7f2015-07-13 07:19:57 -0700113 // Test the wrapped factory for SkSurface by creating a backend texture and then wrap it in
joshualitt81793412015-07-08 12:54:04 -0700114 // a SkSurface.
joshualitt81793412015-07-08 12:54:04 -0700115 static const int kW = 100;
116 static const int kH = 100;
117 static const uint32_t kOrigColor = 0xFFAABBCC;
118 SkAutoTArray<uint32_t> pixels(kW * kH);
119 sk_memset32(pixels.get(), kOrigColor, kW * kH);
jvanverth88957922015-07-14 11:02:52 -0700120 GrBackendObject texID = gpu->createTestingOnlyBackendTexture(pixels.get(), kW, kH,
121 kRGBA_8888_GrPixelConfig);
bsalomone4579ad2015-04-08 08:38:40 -0700122
joshualitt81793412015-07-08 12:54:04 -0700123 GrBackendTextureDesc wrappedDesc;
124 wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
125 wrappedDesc.fWidth = kW;
126 wrappedDesc.fHeight = kH;
127 wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
128 wrappedDesc.fSampleCnt = 0;
129 wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
130 wrappedDesc.fTextureHandle = texID;
bsalomone4579ad2015-04-08 08:38:40 -0700131
joshualitt81793412015-07-08 12:54:04 -0700132 SkAutoTUnref<SkSurface> surface(SkSurface::NewWrappedRenderTarget(ctx, wrappedDesc, NULL));
133 REPORTER_ASSERT(reporter, surface);
134 if (surface) {
135 // Validate that we can draw to the canvas and that the original texture color is preserved
136 // in pixels that aren't rendered to via the surface.
137 SkPaint paint;
138 static const SkColor kRectColor = ~kOrigColor | 0xFF000000;
139 paint.setColor(kRectColor);
140 surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2),
141 paint);
142 SkImageInfo readInfo = SkImageInfo::MakeN32Premul(kW, kH);
143 surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0);
144 bool stop = false;
145 SkPMColor origColorPM = SkPackARGB32((kOrigColor >> 24 & 0xFF),
146 (kOrigColor >> 0 & 0xFF),
147 (kOrigColor >> 8 & 0xFF),
148 (kOrigColor >> 16 & 0xFF));
149 SkPMColor rectColorPM = SkPackARGB32((kRectColor >> 24 & 0xFF),
150 (kRectColor >> 16 & 0xFF),
151 (kRectColor >> 8 & 0xFF),
152 (kRectColor >> 0 & 0xFF));
153 for (int y = 0; y < kH/2 && !stop; ++y) {
154 for (int x = 0; x < kW && !stop; ++x) {
155 REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]);
156 if (rectColorPM != pixels[x + y * kW]) {
157 stop = true;
bsalomon7a617932015-06-16 08:07:16 -0700158 }
159 }
160 }
joshualitt81793412015-07-08 12:54:04 -0700161 stop = false;
162 for (int y = kH/2; y < kH && !stop; ++y) {
163 for (int x = 0; x < kW && !stop; ++x) {
164 REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]);
165 if (origColorPM != pixels[x + y * kW]) {
166 stop = true;
167 }
168 }
bsalomon7a617932015-06-16 08:07:16 -0700169 }
170 }
bsalomone4579ad2015-04-08 08:38:40 -0700171}
172#endif
173
174
reed@google.com999da9c2014-02-06 13:43:07 +0000175static void test_image(skiatest::Reporter* reporter) {
176 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
177 size_t rowBytes = info.minRowBytes();
178 size_t size = info.getSafeSize(rowBytes);
reed9594da12014-09-12 12:12:27 -0700179 SkData* data = SkData::NewUninitialized(size);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000180
mtkleinbbb61d72014-11-24 13:09:39 -0800181 REPORTER_ASSERT(reporter, data->unique());
reed@google.com999da9c2014-02-06 13:43:07 +0000182 SkImage* image = SkImage::NewRasterData(info, data, rowBytes);
mtkleinbbb61d72014-11-24 13:09:39 -0800183 REPORTER_ASSERT(reporter, !data->unique());
reed@google.com999da9c2014-02-06 13:43:07 +0000184 image->unref();
mtkleinbbb61d72014-11-24 13:09:39 -0800185 REPORTER_ASSERT(reporter, data->unique());
reed@google.com999da9c2014-02-06 13:43:07 +0000186 data->unref();
187}
188
reedde499882015-06-18 13:41:40 -0700189// Want to ensure that our Release is called when the owning image is destroyed
190struct ReleaseDataContext {
191 skiatest::Reporter* fReporter;
192 SkData* fData;
193
194 static void Release(const void* pixels, void* context) {
195 ReleaseDataContext* state = (ReleaseDataContext*)context;
196 REPORTER_ASSERT(state->fReporter, state->fData);
197 state->fData->unref();
198 state->fData = NULL;
199 }
200};
201
reed09b2c932015-06-29 14:09:41 -0700202// May we (soon) eliminate the need to keep testing this, by hiding the bloody device!
203#include "SkDevice.h"
204static uint32_t get_legacy_gen_id(SkSurface* surf) {
205 SkBaseDevice* device = surf->getCanvas()->getDevice_just_for_deprecated_compatibility_testing();
206 return device->accessBitmap(false).getGenerationID();
207}
208
reeddca20ce2015-07-03 10:43:43 -0700209/*
210 * Test legacy behavor of bumping the surface's device's bitmap's genID when we access its
211 * texture handle for writing.
212 *
213 * Note: this needs to be tested separately from checking newImageSnapshot, as calling that
214 * can also incidentally bump the genID (when a new backing surface is created).
215 */
joshualitt81793412015-07-08 12:54:04 -0700216template <class F>
217static void test_texture_handle_genID(skiatest::Reporter* reporter, SkSurface* surf, F f) {
reeddca20ce2015-07-03 10:43:43 -0700218 const uint32_t gen0 = get_legacy_gen_id(surf);
joshualitt81793412015-07-08 12:54:04 -0700219 f(surf, SkSurface::kFlushRead_BackendHandleAccess);
reeddca20ce2015-07-03 10:43:43 -0700220 const uint32_t gen1 = get_legacy_gen_id(surf);
221 REPORTER_ASSERT(reporter, gen0 == gen1);
222
joshualitt81793412015-07-08 12:54:04 -0700223 f(surf, SkSurface::kFlushWrite_BackendHandleAccess);
reeddca20ce2015-07-03 10:43:43 -0700224 const uint32_t gen2 = get_legacy_gen_id(surf);
225 REPORTER_ASSERT(reporter, gen0 != gen2);
226
joshualitt81793412015-07-08 12:54:04 -0700227 f(surf, SkSurface::kDiscardWrite_BackendHandleAccess);
reeddca20ce2015-07-03 10:43:43 -0700228 const uint32_t gen3 = get_legacy_gen_id(surf);
229 REPORTER_ASSERT(reporter, gen0 != gen3);
230 REPORTER_ASSERT(reporter, gen2 != gen3);
231}
232
joshualitt81793412015-07-08 12:54:04 -0700233template <class F>
234static void test_backend_handle(skiatest::Reporter* reporter, SkSurface* surf, F f) {
reedfa5e68e2015-06-29 07:37:01 -0700235 SkAutoTUnref<SkImage> image0(surf->newImageSnapshot());
joshualitt81793412015-07-08 12:54:04 -0700236 GrBackendObject obj = f(surf, SkSurface::kFlushRead_BackendHandleAccess);
reedfa5e68e2015-06-29 07:37:01 -0700237 REPORTER_ASSERT(reporter, obj != 0);
238 SkAutoTUnref<SkImage> image1(surf->newImageSnapshot());
239 // just read access should not affect the snapshot
240 REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID());
241
joshualitt81793412015-07-08 12:54:04 -0700242 obj = f(surf, SkSurface::kFlushWrite_BackendHandleAccess);
reedfa5e68e2015-06-29 07:37:01 -0700243 REPORTER_ASSERT(reporter, obj != 0);
244 SkAutoTUnref<SkImage> image2(surf->newImageSnapshot());
245 // expect a new image, since we claimed we would write
246 REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID());
247
joshualitt81793412015-07-08 12:54:04 -0700248 obj = f(surf, SkSurface::kDiscardWrite_BackendHandleAccess);
reedfa5e68e2015-06-29 07:37:01 -0700249 REPORTER_ASSERT(reporter, obj != 0);
250 SkAutoTUnref<SkImage> image3(surf->newImageSnapshot());
251 // expect a new(er) image, since we claimed we would write
252 REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID());
253 REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID());
254}
255
256static SkImage* create_image(skiatest::Reporter* reporter,
257 ImageType imageType, GrContext* context, SkColor color,
bsalomon74f681d2015-06-23 14:38:48 -0700258 ReleaseDataContext* releaseContext) {
reed@google.com4f7c6152014-02-06 14:11:56 +0000259 const SkPMColor pmcolor = SkPreMultiplyColor(color);
260 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
261 const size_t rowBytes = info.minRowBytes();
reede5ea5002014-09-03 11:54:58 -0700262 const size_t size = rowBytes * info.height();
reed@google.com4f7c6152014-02-06 14:11:56 +0000263
reed9594da12014-09-12 12:12:27 -0700264 SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
265 void* addr = data->writable_data();
reed@google.com4f7c6152014-02-06 14:11:56 +0000266 sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2));
reed@google.com4f7c6152014-02-06 14:11:56 +0000267
268 switch (imageType) {
269 case kRasterCopy_ImageType:
270 return SkImage::NewRasterCopy(info, addr, rowBytes);
271 case kRasterData_ImageType:
272 return SkImage::NewRasterData(info, data, rowBytes);
reedde499882015-06-18 13:41:40 -0700273 case kRasterProc_ImageType:
274 SkASSERT(releaseContext);
275 releaseContext->fData = SkRef(data.get());
276 return SkImage::NewFromRaster(info, addr, rowBytes,
277 ReleaseDataContext::Release, releaseContext);
reed67f2eb42014-12-10 06:54:06 -0800278 case kGpu_ImageType: {
bsalomonafe30052015-01-16 07:32:33 -0800279 SkAutoTUnref<SkSurface> surf(
280 SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0));
reed67f2eb42014-12-10 06:54:06 -0800281 surf->getCanvas()->clear(color);
joshualitt81793412015-07-08 12:54:04 -0700282 // test our backing texture / rendertarget while were here...
283 auto textureAccessorFunc =
284 [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject {
285 return surf->getTextureHandle(access); };
286 auto renderTargetAccessorFunc =
287 [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject {
288 GrBackendObject obj;
289 SkAssertResult(surf->getRenderTargetHandle(&obj, access));
290 return obj; };
291 test_backend_handle(reporter, surf, textureAccessorFunc);
292 test_backend_handle(reporter, surf, renderTargetAccessorFunc);
293 test_texture_handle_genID(reporter, surf, textureAccessorFunc);
294 test_texture_handle_genID(reporter, surf, renderTargetAccessorFunc);
295
reedfa5e68e2015-06-29 07:37:01 -0700296 // redraw so our returned image looks as expected.
297 surf->getCanvas()->clear(color);
reed67f2eb42014-12-10 06:54:06 -0800298 return surf->newImageSnapshot();
299 }
reed@google.com4f7c6152014-02-06 14:11:56 +0000300 case kCodec_ImageType: {
301 SkBitmap bitmap;
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +0000302 bitmap.installPixels(info, addr, rowBytes);
reed@google.com4f7c6152014-02-06 14:11:56 +0000303 SkAutoTUnref<SkData> src(
reed67f2eb42014-12-10 06:54:06 -0800304 SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100));
reed871872f2015-06-22 12:48:26 -0700305 return SkImage::NewFromEncoded(src);
reed@google.com4f7c6152014-02-06 14:11:56 +0000306 }
307 }
308 SkASSERT(false);
309 return NULL;
310}
311
reed96472de2014-12-10 09:53:42 -0800312static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) {
313 sk_memset32(pixels, color, count);
314}
315static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) {
316 for (int i = 0; i < count; ++i) {
317 if (pixels[i] != expected) {
318 return false;
319 }
320 }
321 return true;
322}
323
324static void test_image_readpixels(skiatest::Reporter* reporter, SkImage* image,
325 SkPMColor expected) {
326 const SkPMColor notExpected = ~expected;
327
328 const int w = 2, h = 2;
329 const size_t rowBytes = w * sizeof(SkPMColor);
330 SkPMColor pixels[w*h];
331
332 SkImageInfo info;
333
334 info = SkImageInfo::MakeUnknown(w, h);
335 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0));
336
337 // out-of-bounds should fail
338 info = SkImageInfo::MakeN32Premul(w, h);
339 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0));
340 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h));
341 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0));
342 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height()));
343
344 // top-left should succeed
345 set_pixels(pixels, w*h, notExpected);
346 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0));
347 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
348
349 // bottom-right should succeed
350 set_pixels(pixels, w*h, notExpected);
351 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
352 image->width() - w, image->height() - h));
353 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
354
355 // partial top-left should succeed
356 set_pixels(pixels, w*h, notExpected);
357 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1));
358 REPORTER_ASSERT(reporter, pixels[3] == expected);
359 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected));
360
361 // partial bottom-right should succeed
362 set_pixels(pixels, w*h, notExpected);
363 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
364 image->width() - 1, image->height() - 1));
365 REPORTER_ASSERT(reporter, pixels[0] == expected);
366 REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected));
367}
368
fmalitaea561bf2015-07-09 17:10:31 -0700369static void check_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image,
370 const SkBitmap& bitmap, SkImage::LegacyBitmapMode mode) {
371 REPORTER_ASSERT(reporter, image->width() == bitmap.width());
372 REPORTER_ASSERT(reporter, image->height() == bitmap.height());
373 REPORTER_ASSERT(reporter, image->isOpaque() == bitmap.isOpaque());
374
375 if (SkImage::kRO_LegacyBitmapMode == mode) {
376 REPORTER_ASSERT(reporter, bitmap.isImmutable());
377 }
378
379 SkAutoLockPixels alp(bitmap);
380 REPORTER_ASSERT(reporter, bitmap.getPixels());
381
382 const SkImageInfo info = SkImageInfo::MakeN32(1, 1, bitmap.alphaType());
383 SkPMColor imageColor;
384 REPORTER_ASSERT(reporter, image->readPixels(info, &imageColor, sizeof(SkPMColor), 0, 0));
385 REPORTER_ASSERT(reporter, imageColor == *bitmap.getAddr32(0, 0));
386}
387
reed3c065112015-07-08 12:46:22 -0700388static void test_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image) {
389 const SkImage::LegacyBitmapMode modes[] = {
390 SkImage::kRO_LegacyBitmapMode,
391 SkImage::kRW_LegacyBitmapMode,
392 };
393 for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) {
394 SkBitmap bitmap;
395 REPORTER_ASSERT(reporter, image->asLegacyBitmap(&bitmap, modes[i]));
fmalitaea561bf2015-07-09 17:10:31 -0700396 check_legacy_bitmap(reporter, image, bitmap, modes[i]);
reed3c065112015-07-08 12:46:22 -0700397
fmalitaea561bf2015-07-09 17:10:31 -0700398 // Test subsetting to exercise the rowBytes logic.
399 SkBitmap tmp;
400 REPORTER_ASSERT(reporter, bitmap.extractSubset(&tmp, SkIRect::MakeWH(image->width() / 2,
401 image->height() / 2)));
402 SkAutoTUnref<SkImage> subsetImage(SkImage::NewFromBitmap(tmp));
403 REPORTER_ASSERT(reporter, subsetImage);
reed3c065112015-07-08 12:46:22 -0700404
fmalitaea561bf2015-07-09 17:10:31 -0700405 SkBitmap subsetBitmap;
406 REPORTER_ASSERT(reporter, subsetImage->asLegacyBitmap(&subsetBitmap, modes[i]));
407 check_legacy_bitmap(reporter, subsetImage, subsetBitmap, modes[i]);
reed3c065112015-07-08 12:46:22 -0700408 }
409}
410
reed67f2eb42014-12-10 06:54:06 -0800411static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* factory) {
reed@google.com4f7c6152014-02-06 14:11:56 +0000412 static const struct {
413 ImageType fType;
414 bool fPeekShouldSucceed;
reed67f2eb42014-12-10 06:54:06 -0800415 const char* fName;
reed@google.com4f7c6152014-02-06 14:11:56 +0000416 } gRec[] = {
reed67f2eb42014-12-10 06:54:06 -0800417 { kRasterCopy_ImageType, true, "RasterCopy" },
418 { kRasterData_ImageType, true, "RasterData" },
reedde499882015-06-18 13:41:40 -0700419 { kRasterProc_ImageType, true, "RasterProc" },
reed67f2eb42014-12-10 06:54:06 -0800420 { kGpu_ImageType, false, "Gpu" },
421 { kCodec_ImageType, false, "Codec" },
reed@google.com4f7c6152014-02-06 14:11:56 +0000422 };
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000423
reed@google.com4f7c6152014-02-06 14:11:56 +0000424 const SkColor color = SK_ColorRED;
425 const SkPMColor pmcolor = SkPreMultiplyColor(color);
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000426
reed67f2eb42014-12-10 06:54:06 -0800427 GrContext* ctx = NULL;
428#if SK_SUPPORT_GPU
429 ctx = factory->get(GrContextFactory::kNative_GLContextType);
senorblancoc8e93402015-04-21 07:20:36 -0700430 if (NULL == ctx) {
senorblanco84bfd392015-04-21 06:59:17 -0700431 return;
432 }
reed67f2eb42014-12-10 06:54:06 -0800433#endif
434
reedde499882015-06-18 13:41:40 -0700435 ReleaseDataContext releaseCtx;
436 releaseCtx.fReporter = reporter;
437
reed@google.com4f7c6152014-02-06 14:11:56 +0000438 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
439 SkImageInfo info;
440 size_t rowBytes;
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000441
reedde499882015-06-18 13:41:40 -0700442 releaseCtx.fData = NULL;
reedfa5e68e2015-06-29 07:37:01 -0700443 SkAutoTUnref<SkImage> image(create_image(reporter, gRec[i].fType, ctx, color, &releaseCtx));
reed@google.com4f7c6152014-02-06 14:11:56 +0000444 if (!image.get()) {
reed67f2eb42014-12-10 06:54:06 -0800445 SkDebugf("failed to createImage[%d] %s\n", i, gRec[i].fName);
reed@google.com4f7c6152014-02-06 14:11:56 +0000446 continue; // gpu may not be enabled
447 }
reedde499882015-06-18 13:41:40 -0700448 if (kRasterProc_ImageType == gRec[i].fType) {
449 REPORTER_ASSERT(reporter, NULL != releaseCtx.fData); // we are tracking the data
450 } else {
451 REPORTER_ASSERT(reporter, NULL == releaseCtx.fData); // we ignored the context
452 }
453
reed3c065112015-07-08 12:46:22 -0700454 test_legacy_bitmap(reporter, image);
455
reed@google.com4f7c6152014-02-06 14:11:56 +0000456 const void* addr = image->peekPixels(&info, &rowBytes);
bsalomon49f085d2014-09-05 13:34:00 -0700457 bool success = SkToBool(addr);
reed@google.com4f7c6152014-02-06 14:11:56 +0000458 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
459 if (success) {
reede5ea5002014-09-03 11:54:58 -0700460 REPORTER_ASSERT(reporter, 10 == info.width());
461 REPORTER_ASSERT(reporter, 10 == info.height());
462 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType());
463 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() ||
464 kOpaque_SkAlphaType == info.alphaType());
reed@google.com4f7c6152014-02-06 14:11:56 +0000465 REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes);
466 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
467 }
reed96472de2014-12-10 09:53:42 -0800468
469 test_image_readpixels(reporter, image, pmcolor);
reed@google.com4f7c6152014-02-06 14:11:56 +0000470 }
reedde499882015-06-18 13:41:40 -0700471 REPORTER_ASSERT(reporter, NULL == releaseCtx.fData); // we released the data
reed@google.com4f7c6152014-02-06 14:11:56 +0000472}
473
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000474static void test_canvaspeek(skiatest::Reporter* reporter,
475 GrContextFactory* factory) {
476 static const struct {
477 SurfaceType fType;
478 bool fPeekShouldSucceed;
479 } gRec[] = {
480 { kRaster_SurfaceType, true },
481 { kRasterDirect_SurfaceType, true },
482#if SK_SUPPORT_GPU
483 { kGpu_SurfaceType, false },
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000484 { kGpuScratch_SurfaceType, false },
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000485#endif
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000486 };
487
488 const SkColor color = SK_ColorRED;
489 const SkPMColor pmcolor = SkPreMultiplyColor(color);
490
bsalomone904c092014-07-17 10:50:59 -0700491 int cnt;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000492#if SK_SUPPORT_GPU
bsalomone904c092014-07-17 10:50:59 -0700493 cnt = GrContextFactory::kGLContextTypeCnt;
494#else
495 cnt = 1;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000496#endif
497
bsalomone904c092014-07-17 10:50:59 -0700498 for (int i= 0; i < cnt; ++i) {
499 GrContext* context = NULL;
500#if SK_SUPPORT_GPU
501 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
502 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
503 continue;
504 }
505 context = factory->get(glCtxType);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000506
bsalomone904c092014-07-17 10:50:59 -0700507 if (NULL == context) {
508 continue;
509 }
510#endif
511 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
512 SkImageInfo info, requestInfo;
513 size_t rowBytes;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000514
bsalomon74f681d2015-06-23 14:38:48 -0700515 SkAutoTUnref<SkSurface> surface(create_surface(gRec[i].fType, context,
516 kPremul_SkAlphaType, &requestInfo));
bsalomone904c092014-07-17 10:50:59 -0700517 surface->getCanvas()->clear(color);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000518
bsalomone904c092014-07-17 10:50:59 -0700519 const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes);
bsalomon49f085d2014-09-05 13:34:00 -0700520 bool success = SkToBool(addr);
bsalomone904c092014-07-17 10:50:59 -0700521 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000522
bsalomone904c092014-07-17 10:50:59 -0700523 SkImageInfo info2;
524 size_t rb2;
525 const void* addr2 = surface->peekPixels(&info2, &rb2);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000526
bsalomone904c092014-07-17 10:50:59 -0700527 if (success) {
528 REPORTER_ASSERT(reporter, requestInfo == info);
529 REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes);
530 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
531
532 REPORTER_ASSERT(reporter, addr2 == addr);
533 REPORTER_ASSERT(reporter, info2 == info);
534 REPORTER_ASSERT(reporter, rb2 == rowBytes);
535 } else {
536 REPORTER_ASSERT(reporter, NULL == addr2);
537 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000538 }
539 }
540}
541
reed41e010c2015-06-09 12:16:53 -0700542// For compatibility with clients that still call accessBitmap(), we need to ensure that we bump
543// the bitmap's genID when we draw to it, else they won't know it has new values. When they are
544// exclusively using surface/image, and we can hide accessBitmap from device, we can remove this
545// test.
546static void test_accessPixels(skiatest::Reporter* reporter, GrContextFactory* factory) {
547 static const struct {
548 SurfaceType fType;
549 bool fPeekShouldSucceed;
550 } gRec[] = {
551 { kRaster_SurfaceType, true },
552 { kRasterDirect_SurfaceType, true },
553#if SK_SUPPORT_GPU
554 { kGpu_SurfaceType, false },
555 { kGpuScratch_SurfaceType, false },
556#endif
557 };
558
559 int cnt;
560#if SK_SUPPORT_GPU
561 cnt = GrContextFactory::kGLContextTypeCnt;
562#else
563 cnt = 1;
564#endif
565
566 for (int i= 0; i < cnt; ++i) {
567 GrContext* context = NULL;
568#if SK_SUPPORT_GPU
569 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
570 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
571 continue;
572 }
573 context = factory->get(glCtxType);
574
575 if (NULL == context) {
576 continue;
577 }
578#endif
579 for (size_t j = 0; j < SK_ARRAY_COUNT(gRec); ++j) {
580 SkImageInfo info, requestInfo;
581
bsalomon74f681d2015-06-23 14:38:48 -0700582 SkAutoTUnref<SkSurface> surface(create_surface(gRec[j].fType, context,
583 kPremul_SkAlphaType, &requestInfo));
reed41e010c2015-06-09 12:16:53 -0700584 SkCanvas* canvas = surface->getCanvas();
585 canvas->clear(0);
586
587 SkBaseDevice* device = canvas->getDevice_just_for_deprecated_compatibility_testing();
588 SkBitmap bm = device->accessBitmap(false);
589 uint32_t genID0 = bm.getGenerationID();
590 // Now we draw something, which needs to "dirty" the genID (sorta like copy-on-write)
591 canvas->drawColor(SK_ColorBLUE);
592 // Now check that we get a different genID
593 uint32_t genID1 = bm.getGenerationID();
594 REPORTER_ASSERT(reporter, genID0 != genID1);
595 }
596 }
597}
598
bsalomon74f681d2015-06-23 14:38:48 -0700599static void test_snap_alphatype(skiatest::Reporter* reporter, GrContextFactory* factory) {
600 GrContext* context = NULL;
601#if SK_SUPPORT_GPU
602 context = factory->get(GrContextFactory::kNative_GLContextType);
603 if (NULL == context) {
604 return;
605 }
606#endif
607 for (int opaque = 0; opaque < 2; ++opaque) {
608 SkAlphaType atype = SkToBool(opaque) ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
609 for (int st = 0; st < kSurfaceTypeCnt; ++st) {
610 SurfaceType stype = (SurfaceType)st;
611 SkAutoTUnref<SkSurface> surface(create_surface(stype, context, atype));
612 REPORTER_ASSERT(reporter, surface);
613 if (surface) {
614 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
615 REPORTER_ASSERT(reporter, image);
616 if (image) {
617 REPORTER_ASSERT(reporter, image->isOpaque() == SkToBool(opaque));
618 }
619 }
620 }
621 }
622}
623
junov@chromium.org995beb62013-03-28 13:49:22 +0000624static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType,
625 GrContext* context) {
626 // Verify that the right canvas commands trigger a copy on write
bsalomon74f681d2015-06-23 14:38:48 -0700627 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.org995beb62013-03-28 13:49:22 +0000628 SkAutoTUnref<SkSurface> aur_surface(surface);
629 SkCanvas* canvas = surface->getCanvas();
630
631 const SkRect testRect =
632 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
633 SkIntToScalar(4), SkIntToScalar(5));
junov@chromium.org995beb62013-03-28 13:49:22 +0000634 SkPath testPath;
635 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
636 SkIntToScalar(2), SkIntToScalar(1)));
637
638 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1);
639
640 SkRegion testRegion;
641 testRegion.setRect(testIRect);
642
643
644 const SkColor testColor = 0x01020304;
645 const SkPaint testPaint;
646 const SkPoint testPoints[3] = {
647 {SkIntToScalar(0), SkIntToScalar(0)},
648 {SkIntToScalar(2), SkIntToScalar(1)},
649 {SkIntToScalar(0), SkIntToScalar(2)}
650 };
651 const size_t testPointCount = 3;
652
653 SkBitmap testBitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000654 testBitmap.allocN32Pixels(10, 10);
robertphillips@google.comd1ce77d2013-10-09 12:51:09 +0000655 testBitmap.eraseColor(0);
junov@chromium.org995beb62013-03-28 13:49:22 +0000656
657 SkRRect testRRect;
658 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1);
659
660 SkString testText("Hello World");
661 const SkPoint testPoints2[] = {
662 { SkIntToScalar(0), SkIntToScalar(1) },
663 { SkIntToScalar(1), SkIntToScalar(1) },
664 { SkIntToScalar(2), SkIntToScalar(1) },
665 { SkIntToScalar(3), SkIntToScalar(1) },
666 { SkIntToScalar(4), SkIntToScalar(1) },
667 { SkIntToScalar(5), SkIntToScalar(1) },
668 { SkIntToScalar(6), SkIntToScalar(1) },
669 { SkIntToScalar(7), SkIntToScalar(1) },
670 { SkIntToScalar(8), SkIntToScalar(1) },
671 { SkIntToScalar(9), SkIntToScalar(1) },
672 { SkIntToScalar(10), SkIntToScalar(1) },
673 };
674
675#define EXPECT_COPY_ON_WRITE(command) \
676 { \
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000677 SkImage* imageBefore = surface->newImageSnapshot(); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000678 SkAutoTUnref<SkImage> aur_before(imageBefore); \
679 canvas-> command ; \
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000680 SkImage* imageAfter = surface->newImageSnapshot(); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000681 SkAutoTUnref<SkImage> aur_after(imageAfter); \
682 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \
683 }
684
685 EXPECT_COPY_ON_WRITE(clear(testColor))
686 EXPECT_COPY_ON_WRITE(drawPaint(testPaint))
687 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \
688 testPaint))
689 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint))
690 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint))
691 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint))
692 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint))
693 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0))
reed84984ef2015-07-17 07:09:43 -0700694 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, testRect))
junov@chromium.org995beb62013-03-28 13:49:22 +0000695 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL))
696 EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL))
697 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint))
698 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \
699 testPaint))
700 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \
701 testPaint))
702}
703
junov@chromium.orgaf058352013-04-03 15:03:26 +0000704static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter,
705 SurfaceType surfaceType,
706 GrContext* context) {
707 // This test succeeds by not triggering an assertion.
708 // The test verifies that the surface remains writable (usable) after
709 // acquiring and releasing a snapshot without triggering a copy on write.
bsalomon74f681d2015-06-23 14:38:48 -0700710 SkAutoTUnref<SkSurface> surface(create_surface(surfaceType, context));
junov@chromium.orgaf058352013-04-03 15:03:26 +0000711 SkCanvas* canvas = surface->getCanvas();
712 canvas->clear(1);
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000713 surface->newImageSnapshot()->unref(); // Create and destroy SkImage
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000714 canvas->clear(2); // Must not assert internally
junov@chromium.org995beb62013-03-28 13:49:22 +0000715}
junov@chromium.orgda904742013-05-01 22:38:16 +0000716
junov@chromium.orgb516a412013-05-01 22:49:59 +0000717#if SK_SUPPORT_GPU
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000718static void Test_crbug263329(skiatest::Reporter* reporter,
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000719 SurfaceType surfaceType,
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000720 GrContext* context) {
721 // This is a regression test for crbug.com/263329
722 // Bug was caused by onCopyOnWrite releasing the old surface texture
723 // back to the scratch texture pool even though the texture is used
724 // by and active SkImage_Gpu.
bsalomon74f681d2015-06-23 14:38:48 -0700725 SkAutoTUnref<SkSurface> surface1(create_surface(surfaceType, context));
726 SkAutoTUnref<SkSurface> surface2(create_surface(surfaceType, context));
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000727 SkCanvas* canvas1 = surface1->getCanvas();
728 SkCanvas* canvas2 = surface2->getCanvas();
729 canvas1->clear(1);
730 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot());
731 // Trigger copy on write, new backing is a scratch texture
732 canvas1->clear(2);
733 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot());
734 // Trigger copy on write, old backing should not be returned to scratch
735 // pool because it is held by image2
736 canvas1->clear(3);
737
738 canvas2->clear(4);
739 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot());
740 // Trigger copy on write on surface2. The new backing store should not
741 // be recycling a texture that is held by an existing image.
742 canvas2->clear(5);
743 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot());
bsalomon55812362015-06-10 08:49:28 -0700744 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image3)->getTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000745 // The following assertion checks crbug.com/263329
bsalomon55812362015-06-10 08:49:28 -0700746 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image2)->getTexture());
747 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image1)->getTexture());
748 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image2)->getTexture());
749 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image1)->getTexture());
750 REPORTER_ASSERT(reporter, as_IB(image2)->getTexture() != as_IB(image1)->getTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000751}
752
junov@chromium.orgda904742013-05-01 22:38:16 +0000753static void TestGetTexture(skiatest::Reporter* reporter,
754 SurfaceType surfaceType,
755 GrContext* context) {
bsalomon74f681d2015-06-23 14:38:48 -0700756 SkAutoTUnref<SkSurface> surface(create_surface(surfaceType, context));
junov@chromium.orgda904742013-05-01 22:38:16 +0000757 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
bsalomon55812362015-06-10 08:49:28 -0700758 GrTexture* texture = as_IB(image)->getTexture();
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000759 if (surfaceType == kGpu_SurfaceType || surfaceType == kGpuScratch_SurfaceType) {
bsalomon49f085d2014-09-05 13:34:00 -0700760 REPORTER_ASSERT(reporter, texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000761 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle());
762 } else {
763 REPORTER_ASSERT(reporter, NULL == texture);
764 }
765 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
bsalomon55812362015-06-10 08:49:28 -0700766 REPORTER_ASSERT(reporter, as_IB(image)->getTexture() == texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000767}
bsalomoneaaaf0b2015-01-23 08:08:04 -0800768
bsalomon3582d3e2015-02-13 14:20:05 -0800769#include "GrGpuResourcePriv.h"
bsalomoneaaaf0b2015-01-23 08:08:04 -0800770#include "SkGpuDevice.h"
771#include "SkImage_Gpu.h"
772#include "SkSurface_Gpu.h"
773
774SkSurface::Budgeted is_budgeted(SkSurface* surf) {
bsalomon3582d3e2015-02-13 14:20:05 -0800775 return ((SkSurface_Gpu*)surf)->getDevice()->accessRenderTarget()->resourcePriv().isBudgeted() ?
bsalomoneaaaf0b2015-01-23 08:08:04 -0800776 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
777}
778
779SkSurface::Budgeted is_budgeted(SkImage* image) {
bsalomon3582d3e2015-02-13 14:20:05 -0800780 return ((SkImage_Gpu*)image)->getTexture()->resourcePriv().isBudgeted() ?
bsalomoneaaaf0b2015-01-23 08:08:04 -0800781 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
782}
783
784static void test_surface_budget(skiatest::Reporter* reporter, GrContext* context) {
785 SkImageInfo info = SkImageInfo::MakeN32Premul(8,8);
786 for (int i = 0; i < 2; ++i) {
787 SkSurface::Budgeted sbudgeted = i ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
788 for (int j = 0; j < 2; ++j) {
789 SkSurface::Budgeted ibudgeted = j ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
790 SkAutoTUnref<SkSurface>
791 surface(SkSurface::NewRenderTarget(context, sbudgeted, info, 0));
792 SkASSERT(surface);
793 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
794
mtklein31ff2982015-01-24 11:27:27 -0800795 SkAutoTUnref<SkImage> image(surface->newImageSnapshot(ibudgeted));
bsalomoneaaaf0b2015-01-23 08:08:04 -0800796
797 // Initially the image shares a texture with the surface, and the surface decides
798 // whether it is budgeted or not.
799 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
800 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(image));
801
802 // Now trigger copy-on-write
803 surface->getCanvas()->clear(SK_ColorBLUE);
804
805 // They don't share a texture anymore. They should each have made their own budget
806 // decision.
807 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
808 REPORTER_ASSERT(reporter, ibudgeted == is_budgeted(image));
809 }
810 }
811}
812
junov@chromium.orgb516a412013-05-01 22:49:59 +0000813#endif
junov@chromium.orgda904742013-05-01 22:38:16 +0000814
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000815static void TestSurfaceNoCanvas(skiatest::Reporter* reporter,
816 SurfaceType surfaceType,
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000817 GrContext* context,
818 SkSurface::ContentChangeMode mode) {
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000819 // Verifies the robustness of SkSurface for handling use cases where calls
820 // are made before a canvas is created.
821 {
822 // Test passes by not asserting
bsalomon74f681d2015-06-23 14:38:48 -0700823 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000824 SkAutoTUnref<SkSurface> aur_surface(surface);
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000825 surface->notifyContentWillChange(mode);
robertphillips@google.com03087072013-10-02 16:42:21 +0000826 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000827 }
828 {
bsalomon74f681d2015-06-23 14:38:48 -0700829 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000830 SkAutoTUnref<SkSurface> aur_surface(surface);
831 SkImage* image1 = surface->newImageSnapshot();
832 SkAutoTUnref<SkImage> aur_image1(image1);
robertphillips@google.com03087072013-10-02 16:42:21 +0000833 SkDEBUGCODE(image1->validate();)
834 SkDEBUGCODE(surface->validate();)
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000835 surface->notifyContentWillChange(mode);
robertphillips@google.com03087072013-10-02 16:42:21 +0000836 SkDEBUGCODE(image1->validate();)
837 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000838 SkImage* image2 = surface->newImageSnapshot();
839 SkAutoTUnref<SkImage> aur_image2(image2);
robertphillips@google.com03087072013-10-02 16:42:21 +0000840 SkDEBUGCODE(image2->validate();)
841 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000842 REPORTER_ASSERT(reporter, image1 != image2);
843 }
skia.committer@gmail.com45fb8b62013-04-17 07:00:56 +0000844
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000845}
junov@chromium.org995beb62013-03-28 13:49:22 +0000846
tfarina@chromium.org4ee16bf2014-01-10 22:08:27 +0000847DEF_GPUTEST(Surface, reporter, factory) {
reed@google.com999da9c2014-02-06 13:43:07 +0000848 test_image(reporter);
849
junov@chromium.orgaf058352013-04-03 15:03:26 +0000850 TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL);
junov@chromium.orgaf058352013-04-03 15:03:26 +0000851 TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL);
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000852 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode);
853 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000854
reedb2497c22014-12-31 12:31:43 -0800855 test_empty_image(reporter);
856 test_empty_surface(reporter, NULL);
857
reed67f2eb42014-12-10 06:54:06 -0800858 test_imagepeek(reporter, factory);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000859 test_canvaspeek(reporter, factory);
860
reed41e010c2015-06-09 12:16:53 -0700861 test_accessPixels(reporter, factory);
862
bsalomon74f681d2015-06-23 14:38:48 -0700863 test_snap_alphatype(reporter, factory);
864
junov@chromium.orgb516a412013-05-01 22:49:59 +0000865#if SK_SUPPORT_GPU
junov@chromium.orgda904742013-05-01 22:38:16 +0000866 TestGetTexture(reporter, kRaster_SurfaceType, NULL);
bsalomon49f085d2014-09-05 13:34:00 -0700867 if (factory) {
bsalomone904c092014-07-17 10:50:59 -0700868 for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
869 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
870 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
871 continue;
872 }
873 GrContext* context = factory->get(glCtxType);
bsalomon49f085d2014-09-05 13:34:00 -0700874 if (context) {
bsalomone904c092014-07-17 10:50:59 -0700875 Test_crbug263329(reporter, kGpu_SurfaceType, context);
876 Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
877 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
878 TestSurfaceCopyOnWrite(reporter, kGpuScratch_SurfaceType, context);
879 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context);
880 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpuScratch_SurfaceType, context);
881 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
882 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
883 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
884 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
885 TestGetTexture(reporter, kGpu_SurfaceType, context);
886 TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
reedb2497c22014-12-31 12:31:43 -0800887 test_empty_surface(reporter, context);
bsalomoneaaaf0b2015-01-23 08:08:04 -0800888 test_surface_budget(reporter, context);
joshualitt81793412015-07-08 12:54:04 -0700889 test_wrapped_texture_surface(reporter, context);
bsalomone904c092014-07-17 10:50:59 -0700890 }
robertphillips@google.com3bddb382013-11-12 13:51:03 +0000891 }
junov@chromium.orgaf058352013-04-03 15:03:26 +0000892 }
junov@chromium.org995beb62013-03-28 13:49:22 +0000893#endif
894}
reed8b26b992015-05-07 15:36:17 -0700895
896#if SK_SUPPORT_GPU
reedde499882015-06-18 13:41:40 -0700897
898struct ReleaseTextureContext {
899 ReleaseTextureContext(skiatest::Reporter* reporter) {
900 fReporter = reporter;
901 fIsReleased = false;
902 }
903
904 skiatest::Reporter* fReporter;
905 bool fIsReleased;
906
907 void doRelease() {
908 REPORTER_ASSERT(fReporter, false == fIsReleased);
909 fIsReleased = true;
910 }
911
912 static void ReleaseProc(void* context) {
913 ((ReleaseTextureContext*)context)->doRelease();
914 }
915};
916
917static SkImage* make_desc_image(GrContext* ctx, int w, int h, GrBackendObject texID,
918 ReleaseTextureContext* releaseContext) {
reed8b26b992015-05-07 15:36:17 -0700919 GrBackendTextureDesc desc;
920 desc.fConfig = kSkia8888_GrPixelConfig;
921 // need to be a rendertarget for now...
922 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
923 desc.fWidth = w;
924 desc.fHeight = h;
925 desc.fSampleCnt = 0;
926 desc.fTextureHandle = texID;
reedde499882015-06-18 13:41:40 -0700927 return releaseContext
928 ? SkImage::NewFromTexture(ctx, desc, kPremul_SkAlphaType,
929 ReleaseTextureContext::ReleaseProc, releaseContext)
930 : SkImage::NewFromTextureCopy(ctx, desc, kPremul_SkAlphaType);
reed8b26b992015-05-07 15:36:17 -0700931}
932
933static void test_image_color(skiatest::Reporter* reporter, SkImage* image, SkPMColor expected) {
934 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
935 SkPMColor pixel;
936 REPORTER_ASSERT(reporter, image->readPixels(info, &pixel, sizeof(pixel), 0, 0));
937 REPORTER_ASSERT(reporter, pixel == expected);
938}
939
940DEF_GPUTEST(SkImage_NewFromTexture, reporter, factory) {
941 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
942 if (!ctx) {
943 REPORTER_ASSERT(reporter, false);
944 return;
945 }
946 GrTextureProvider* provider = ctx->textureProvider();
947
948 const int w = 10;
949 const int h = 10;
950 SkPMColor storage[w * h];
951 const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED);
952 sk_memset32(storage, expected0, w * h);
953
954 GrSurfaceDesc desc;
bsalomonbea01502015-07-16 10:00:28 -0700955 desc.fFlags = kRenderTarget_GrSurfaceFlag; // needs to be a rendertarget for readpixels();
reed8b26b992015-05-07 15:36:17 -0700956 desc.fOrigin = kDefault_GrSurfaceOrigin;
957 desc.fWidth = w;
958 desc.fHeight = h;
959 desc.fConfig = kSkia8888_GrPixelConfig;
960 desc.fSampleCnt = 0;
961
962 SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, false, storage, w * 4));
963 if (!tex) {
964 REPORTER_ASSERT(reporter, false);
965 return;
966 }
reedde499882015-06-18 13:41:40 -0700967
reed8b26b992015-05-07 15:36:17 -0700968 GrBackendObject srcTex = tex->getTextureHandle();
reedde499882015-06-18 13:41:40 -0700969 ReleaseTextureContext releaseCtx(reporter);
970
971 SkAutoTUnref<SkImage> refImg(make_desc_image(ctx, w, h, srcTex, &releaseCtx));
972 SkAutoTUnref<SkImage> cpyImg(make_desc_image(ctx, w, h, srcTex, NULL));
reed8b26b992015-05-07 15:36:17 -0700973
974 test_image_color(reporter, refImg, expected0);
975 test_image_color(reporter, cpyImg, expected0);
976
977 // Now lets jam new colors into our "external" texture, and see if the images notice
978 const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE);
979 sk_memset32(storage, expected1, w * h);
980 tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp);
981
982 // We expect the ref'd image to see the new color, but cpy'd one should still see the old color
983 test_image_color(reporter, refImg, expected1);
984 test_image_color(reporter, cpyImg, expected0);
reedde499882015-06-18 13:41:40 -0700985
986 // Now exercise the release proc
987 REPORTER_ASSERT(reporter, !releaseCtx.fIsReleased);
988 refImg.reset(NULL); // force a release of the image
989 REPORTER_ASSERT(reporter, releaseCtx.fIsReleased);
reed8b26b992015-05-07 15:36:17 -0700990}
991#endif