blob: 57ad5e0ca8340462ac2ddb9f80ca40ee97b66370 [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"
21#include "gl/GrGLInterface.h"
22#include "gl/GrGLUtil.h"
junov@chromium.org995beb62013-03-28 13:49:22 +000023#else
24class GrContextFactory;
25class GrContext;
26#endif
27
28enum SurfaceType {
29 kRaster_SurfaceType,
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000030 kRasterDirect_SurfaceType,
junov@chromium.org995beb62013-03-28 13:49:22 +000031 kGpu_SurfaceType,
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +000032 kGpuScratch_SurfaceType,
bsalomon74f681d2015-06-23 14:38:48 -070033
34 kLastSurfaceType = kGpuScratch_SurfaceType
junov@chromium.org995beb62013-03-28 13:49:22 +000035};
bsalomon74f681d2015-06-23 14:38:48 -070036static const int kSurfaceTypeCnt = kLastSurfaceType + 1;
junov@chromium.org995beb62013-03-28 13:49:22 +000037
reed982542d2014-06-27 06:48:14 -070038static void release_storage(void* pixels, void* context) {
39 SkASSERT(pixels == context);
40 sk_free(pixels);
41}
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000042
bsalomon74f681d2015-06-23 14:38:48 -070043static SkSurface* create_surface(SurfaceType surfaceType, GrContext* context,
44 SkAlphaType at = kPremul_SkAlphaType,
45 SkImageInfo* requestedInfo = NULL) {
46 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000047
48 if (requestedInfo) {
49 *requestedInfo = info;
50 }
junov@chromium.org995beb62013-03-28 13:49:22 +000051
52 switch (surfaceType) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000053 case kRaster_SurfaceType:
54 return SkSurface::NewRaster(info);
reed982542d2014-06-27 06:48:14 -070055 case kRasterDirect_SurfaceType: {
56 const size_t rowBytes = info.minRowBytes();
57 void* storage = sk_malloc_throw(info.getSafeSize(rowBytes));
58 return SkSurface::NewRasterDirectReleaseProc(info, storage, rowBytes,
59 release_storage, storage);
60 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000061 case kGpu_SurfaceType:
bsalomonafe30052015-01-16 07:32:33 -080062 return SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0, NULL);
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +000063 case kGpuScratch_SurfaceType:
bsalomonafe30052015-01-16 07:32:33 -080064 return SkSurface::NewRenderTarget(context, SkSurface::kYes_Budgeted, info, 0, NULL);
junov@chromium.org995beb62013-03-28 13:49:22 +000065 }
junov@chromium.org995beb62013-03-28 13:49:22 +000066 return NULL;
67}
68
reed@google.com4f7c6152014-02-06 14:11:56 +000069enum ImageType {
70 kRasterCopy_ImageType,
71 kRasterData_ImageType,
reedde499882015-06-18 13:41:40 -070072 kRasterProc_ImageType,
reed@google.com4f7c6152014-02-06 14:11:56 +000073 kGpu_ImageType,
reed@google.com4f7c6152014-02-06 14:11:56 +000074 kCodec_ImageType,
75};
reed@google.com999da9c2014-02-06 13:43:07 +000076
reedb2497c22014-12-31 12:31:43 -080077#include "SkImageGenerator.h"
78
79class EmptyGenerator : public SkImageGenerator {
reed3ef71e32015-03-19 08:31:14 -070080public:
81 EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {}
reedb2497c22014-12-31 12:31:43 -080082};
83
84static void test_empty_image(skiatest::Reporter* reporter) {
85 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
86
87 REPORTER_ASSERT(reporter, NULL == SkImage::NewRasterCopy(info, NULL, 0));
88 REPORTER_ASSERT(reporter, NULL == SkImage::NewRasterData(info, NULL, 0));
reedde499882015-06-18 13:41:40 -070089 REPORTER_ASSERT(reporter, NULL == SkImage::NewFromRaster(info, NULL, 0, NULL, NULL));
reedb2497c22014-12-31 12:31:43 -080090 REPORTER_ASSERT(reporter, NULL == SkImage::NewFromGenerator(SkNEW(EmptyGenerator)));
91}
92
93static void test_empty_surface(skiatest::Reporter* reporter, GrContext* ctx) {
94 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
95
96 REPORTER_ASSERT(reporter, NULL == SkSurface::NewRaster(info));
97 REPORTER_ASSERT(reporter, NULL == SkSurface::NewRasterDirect(info, NULL, 0));
98 if (ctx) {
bsalomonafe30052015-01-16 07:32:33 -080099 REPORTER_ASSERT(reporter, NULL ==
100 SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info, 0, NULL));
reedb2497c22014-12-31 12:31:43 -0800101 }
102}
103
bsalomone4579ad2015-04-08 08:38:40 -0700104#if SK_SUPPORT_GPU
joshualitt81793412015-07-08 12:54:04 -0700105static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext* ctx) {
bsalomone4579ad2015-04-08 08:38:40 -0700106 if (NULL == ctx) {
107 return;
108 }
bsalomone4579ad2015-04-08 08:38:40 -0700109
bsalomon7a617932015-06-16 08:07:16 -0700110 GrTestTarget tt;
111 ctx->getTestTarget(&tt);
112 if (!tt.target()) {
113 SkDEBUGFAIL("Couldn't get Gr test target.");
bsalomone4579ad2015-04-08 08:38:40 -0700114 return;
115 }
bsalomon7a617932015-06-16 08:07:16 -0700116
117 // We currently have only implemented the texture uploads for GL.
reedf9ad5582015-06-25 21:29:25 -0700118 const GrGLInterface* gl = tt.glContext()->interface();
bsalomon7a617932015-06-16 08:07:16 -0700119 if (!gl) {
120 return;
121 }
122
joshualitt81793412015-07-08 12:54:04 -0700123 // Test the wrapped factory for SkSurface by creating a texture using GL and then wrap it in
124 // a SkSurface.
125 GrGLuint texID;
126 static const int kW = 100;
127 static const int kH = 100;
128 static const uint32_t kOrigColor = 0xFFAABBCC;
129 SkAutoTArray<uint32_t> pixels(kW * kH);
130 sk_memset32(pixels.get(), kOrigColor, kW * kH);
131 GR_GL_CALL(gl, GenTextures(1, &texID));
132 GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE0));
133 GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
134 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texID));
135 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER,
136 GR_GL_NEAREST));
137 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER,
138 GR_GL_NEAREST));
139 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S,
140 GR_GL_CLAMP_TO_EDGE));
141 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T,
142 GR_GL_CLAMP_TO_EDGE));
143 GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RGBA, kW, kH, 0, GR_GL_RGBA,
144 GR_GL_UNSIGNED_BYTE,
145 pixels.get()));
bsalomone4579ad2015-04-08 08:38:40 -0700146
joshualitt81793412015-07-08 12:54:04 -0700147 GrBackendTextureDesc wrappedDesc;
148 wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
149 wrappedDesc.fWidth = kW;
150 wrappedDesc.fHeight = kH;
151 wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
152 wrappedDesc.fSampleCnt = 0;
153 wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
154 wrappedDesc.fTextureHandle = texID;
bsalomone4579ad2015-04-08 08:38:40 -0700155
joshualitt81793412015-07-08 12:54:04 -0700156 SkAutoTUnref<SkSurface> surface(SkSurface::NewWrappedRenderTarget(ctx, wrappedDesc, NULL));
157 REPORTER_ASSERT(reporter, surface);
158 if (surface) {
159 // Validate that we can draw to the canvas and that the original texture color is preserved
160 // in pixels that aren't rendered to via the surface.
161 SkPaint paint;
162 static const SkColor kRectColor = ~kOrigColor | 0xFF000000;
163 paint.setColor(kRectColor);
164 surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2),
165 paint);
166 SkImageInfo readInfo = SkImageInfo::MakeN32Premul(kW, kH);
167 surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0);
168 bool stop = false;
169 SkPMColor origColorPM = SkPackARGB32((kOrigColor >> 24 & 0xFF),
170 (kOrigColor >> 0 & 0xFF),
171 (kOrigColor >> 8 & 0xFF),
172 (kOrigColor >> 16 & 0xFF));
173 SkPMColor rectColorPM = SkPackARGB32((kRectColor >> 24 & 0xFF),
174 (kRectColor >> 16 & 0xFF),
175 (kRectColor >> 8 & 0xFF),
176 (kRectColor >> 0 & 0xFF));
177 for (int y = 0; y < kH/2 && !stop; ++y) {
178 for (int x = 0; x < kW && !stop; ++x) {
179 REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]);
180 if (rectColorPM != pixels[x + y * kW]) {
181 stop = true;
bsalomon7a617932015-06-16 08:07:16 -0700182 }
183 }
184 }
joshualitt81793412015-07-08 12:54:04 -0700185 stop = false;
186 for (int y = kH/2; y < kH && !stop; ++y) {
187 for (int x = 0; x < kW && !stop; ++x) {
188 REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]);
189 if (origColorPM != pixels[x + y * kW]) {
190 stop = true;
191 }
192 }
bsalomon7a617932015-06-16 08:07:16 -0700193 }
194 }
bsalomone4579ad2015-04-08 08:38:40 -0700195}
196#endif
197
198
reed@google.com999da9c2014-02-06 13:43:07 +0000199static void test_image(skiatest::Reporter* reporter) {
200 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
201 size_t rowBytes = info.minRowBytes();
202 size_t size = info.getSafeSize(rowBytes);
reed9594da12014-09-12 12:12:27 -0700203 SkData* data = SkData::NewUninitialized(size);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000204
mtkleinbbb61d72014-11-24 13:09:39 -0800205 REPORTER_ASSERT(reporter, data->unique());
reed@google.com999da9c2014-02-06 13:43:07 +0000206 SkImage* image = SkImage::NewRasterData(info, data, rowBytes);
mtkleinbbb61d72014-11-24 13:09:39 -0800207 REPORTER_ASSERT(reporter, !data->unique());
reed@google.com999da9c2014-02-06 13:43:07 +0000208 image->unref();
mtkleinbbb61d72014-11-24 13:09:39 -0800209 REPORTER_ASSERT(reporter, data->unique());
reed@google.com999da9c2014-02-06 13:43:07 +0000210 data->unref();
211}
212
reedde499882015-06-18 13:41:40 -0700213// Want to ensure that our Release is called when the owning image is destroyed
214struct ReleaseDataContext {
215 skiatest::Reporter* fReporter;
216 SkData* fData;
217
218 static void Release(const void* pixels, void* context) {
219 ReleaseDataContext* state = (ReleaseDataContext*)context;
220 REPORTER_ASSERT(state->fReporter, state->fData);
221 state->fData->unref();
222 state->fData = NULL;
223 }
224};
225
reed09b2c932015-06-29 14:09:41 -0700226// May we (soon) eliminate the need to keep testing this, by hiding the bloody device!
227#include "SkDevice.h"
228static uint32_t get_legacy_gen_id(SkSurface* surf) {
229 SkBaseDevice* device = surf->getCanvas()->getDevice_just_for_deprecated_compatibility_testing();
230 return device->accessBitmap(false).getGenerationID();
231}
232
reeddca20ce2015-07-03 10:43:43 -0700233/*
234 * Test legacy behavor of bumping the surface's device's bitmap's genID when we access its
235 * texture handle for writing.
236 *
237 * Note: this needs to be tested separately from checking newImageSnapshot, as calling that
238 * can also incidentally bump the genID (when a new backing surface is created).
239 */
joshualitt81793412015-07-08 12:54:04 -0700240template <class F>
241static void test_texture_handle_genID(skiatest::Reporter* reporter, SkSurface* surf, F f) {
reeddca20ce2015-07-03 10:43:43 -0700242 const uint32_t gen0 = get_legacy_gen_id(surf);
joshualitt81793412015-07-08 12:54:04 -0700243 f(surf, SkSurface::kFlushRead_BackendHandleAccess);
reeddca20ce2015-07-03 10:43:43 -0700244 const uint32_t gen1 = get_legacy_gen_id(surf);
245 REPORTER_ASSERT(reporter, gen0 == gen1);
246
joshualitt81793412015-07-08 12:54:04 -0700247 f(surf, SkSurface::kFlushWrite_BackendHandleAccess);
reeddca20ce2015-07-03 10:43:43 -0700248 const uint32_t gen2 = get_legacy_gen_id(surf);
249 REPORTER_ASSERT(reporter, gen0 != gen2);
250
joshualitt81793412015-07-08 12:54:04 -0700251 f(surf, SkSurface::kDiscardWrite_BackendHandleAccess);
reeddca20ce2015-07-03 10:43:43 -0700252 const uint32_t gen3 = get_legacy_gen_id(surf);
253 REPORTER_ASSERT(reporter, gen0 != gen3);
254 REPORTER_ASSERT(reporter, gen2 != gen3);
255}
256
joshualitt81793412015-07-08 12:54:04 -0700257template <class F>
258static void test_backend_handle(skiatest::Reporter* reporter, SkSurface* surf, F f) {
reedfa5e68e2015-06-29 07:37:01 -0700259 SkAutoTUnref<SkImage> image0(surf->newImageSnapshot());
joshualitt81793412015-07-08 12:54:04 -0700260 GrBackendObject obj = f(surf, SkSurface::kFlushRead_BackendHandleAccess);
reedfa5e68e2015-06-29 07:37:01 -0700261 REPORTER_ASSERT(reporter, obj != 0);
262 SkAutoTUnref<SkImage> image1(surf->newImageSnapshot());
263 // just read access should not affect the snapshot
264 REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID());
265
joshualitt81793412015-07-08 12:54:04 -0700266 obj = f(surf, SkSurface::kFlushWrite_BackendHandleAccess);
reedfa5e68e2015-06-29 07:37:01 -0700267 REPORTER_ASSERT(reporter, obj != 0);
268 SkAutoTUnref<SkImage> image2(surf->newImageSnapshot());
269 // expect a new image, since we claimed we would write
270 REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID());
271
joshualitt81793412015-07-08 12:54:04 -0700272 obj = f(surf, SkSurface::kDiscardWrite_BackendHandleAccess);
reedfa5e68e2015-06-29 07:37:01 -0700273 REPORTER_ASSERT(reporter, obj != 0);
274 SkAutoTUnref<SkImage> image3(surf->newImageSnapshot());
275 // expect a new(er) image, since we claimed we would write
276 REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID());
277 REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID());
278}
279
280static SkImage* create_image(skiatest::Reporter* reporter,
281 ImageType imageType, GrContext* context, SkColor color,
bsalomon74f681d2015-06-23 14:38:48 -0700282 ReleaseDataContext* releaseContext) {
reed@google.com4f7c6152014-02-06 14:11:56 +0000283 const SkPMColor pmcolor = SkPreMultiplyColor(color);
284 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
285 const size_t rowBytes = info.minRowBytes();
reede5ea5002014-09-03 11:54:58 -0700286 const size_t size = rowBytes * info.height();
reed@google.com4f7c6152014-02-06 14:11:56 +0000287
reed9594da12014-09-12 12:12:27 -0700288 SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
289 void* addr = data->writable_data();
reed@google.com4f7c6152014-02-06 14:11:56 +0000290 sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2));
reed@google.com4f7c6152014-02-06 14:11:56 +0000291
292 switch (imageType) {
293 case kRasterCopy_ImageType:
294 return SkImage::NewRasterCopy(info, addr, rowBytes);
295 case kRasterData_ImageType:
296 return SkImage::NewRasterData(info, data, rowBytes);
reedde499882015-06-18 13:41:40 -0700297 case kRasterProc_ImageType:
298 SkASSERT(releaseContext);
299 releaseContext->fData = SkRef(data.get());
300 return SkImage::NewFromRaster(info, addr, rowBytes,
301 ReleaseDataContext::Release, releaseContext);
reed67f2eb42014-12-10 06:54:06 -0800302 case kGpu_ImageType: {
bsalomonafe30052015-01-16 07:32:33 -0800303 SkAutoTUnref<SkSurface> surf(
304 SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0));
reed67f2eb42014-12-10 06:54:06 -0800305 surf->getCanvas()->clear(color);
joshualitt81793412015-07-08 12:54:04 -0700306 // test our backing texture / rendertarget while were here...
307 auto textureAccessorFunc =
308 [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject {
309 return surf->getTextureHandle(access); };
310 auto renderTargetAccessorFunc =
311 [](SkSurface* surf, SkSurface::BackendHandleAccess access) -> GrBackendObject {
312 GrBackendObject obj;
313 SkAssertResult(surf->getRenderTargetHandle(&obj, access));
314 return obj; };
315 test_backend_handle(reporter, surf, textureAccessorFunc);
316 test_backend_handle(reporter, surf, renderTargetAccessorFunc);
317 test_texture_handle_genID(reporter, surf, textureAccessorFunc);
318 test_texture_handle_genID(reporter, surf, renderTargetAccessorFunc);
319
reedfa5e68e2015-06-29 07:37:01 -0700320 // redraw so our returned image looks as expected.
321 surf->getCanvas()->clear(color);
reed67f2eb42014-12-10 06:54:06 -0800322 return surf->newImageSnapshot();
323 }
reed@google.com4f7c6152014-02-06 14:11:56 +0000324 case kCodec_ImageType: {
325 SkBitmap bitmap;
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +0000326 bitmap.installPixels(info, addr, rowBytes);
reed@google.com4f7c6152014-02-06 14:11:56 +0000327 SkAutoTUnref<SkData> src(
reed67f2eb42014-12-10 06:54:06 -0800328 SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100));
reed871872f2015-06-22 12:48:26 -0700329 return SkImage::NewFromEncoded(src);
reed@google.com4f7c6152014-02-06 14:11:56 +0000330 }
331 }
332 SkASSERT(false);
333 return NULL;
334}
335
reed96472de2014-12-10 09:53:42 -0800336static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) {
337 sk_memset32(pixels, color, count);
338}
339static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) {
340 for (int i = 0; i < count; ++i) {
341 if (pixels[i] != expected) {
342 return false;
343 }
344 }
345 return true;
346}
347
348static void test_image_readpixels(skiatest::Reporter* reporter, SkImage* image,
349 SkPMColor expected) {
350 const SkPMColor notExpected = ~expected;
351
352 const int w = 2, h = 2;
353 const size_t rowBytes = w * sizeof(SkPMColor);
354 SkPMColor pixels[w*h];
355
356 SkImageInfo info;
357
358 info = SkImageInfo::MakeUnknown(w, h);
359 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0));
360
361 // out-of-bounds should fail
362 info = SkImageInfo::MakeN32Premul(w, h);
363 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0));
364 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h));
365 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0));
366 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height()));
367
368 // top-left should succeed
369 set_pixels(pixels, w*h, notExpected);
370 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0));
371 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
372
373 // bottom-right should succeed
374 set_pixels(pixels, w*h, notExpected);
375 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
376 image->width() - w, image->height() - h));
377 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
378
379 // partial top-left should succeed
380 set_pixels(pixels, w*h, notExpected);
381 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1));
382 REPORTER_ASSERT(reporter, pixels[3] == expected);
383 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected));
384
385 // partial bottom-right should succeed
386 set_pixels(pixels, w*h, notExpected);
387 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
388 image->width() - 1, image->height() - 1));
389 REPORTER_ASSERT(reporter, pixels[0] == expected);
390 REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected));
391}
392
fmalitaea561bf2015-07-09 17:10:31 -0700393static void check_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image,
394 const SkBitmap& bitmap, SkImage::LegacyBitmapMode mode) {
395 REPORTER_ASSERT(reporter, image->width() == bitmap.width());
396 REPORTER_ASSERT(reporter, image->height() == bitmap.height());
397 REPORTER_ASSERT(reporter, image->isOpaque() == bitmap.isOpaque());
398
399 if (SkImage::kRO_LegacyBitmapMode == mode) {
400 REPORTER_ASSERT(reporter, bitmap.isImmutable());
401 }
402
403 SkAutoLockPixels alp(bitmap);
404 REPORTER_ASSERT(reporter, bitmap.getPixels());
405
406 const SkImageInfo info = SkImageInfo::MakeN32(1, 1, bitmap.alphaType());
407 SkPMColor imageColor;
408 REPORTER_ASSERT(reporter, image->readPixels(info, &imageColor, sizeof(SkPMColor), 0, 0));
409 REPORTER_ASSERT(reporter, imageColor == *bitmap.getAddr32(0, 0));
410}
411
reed3c065112015-07-08 12:46:22 -0700412static void test_legacy_bitmap(skiatest::Reporter* reporter, const SkImage* image) {
413 const SkImage::LegacyBitmapMode modes[] = {
414 SkImage::kRO_LegacyBitmapMode,
415 SkImage::kRW_LegacyBitmapMode,
416 };
417 for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) {
418 SkBitmap bitmap;
419 REPORTER_ASSERT(reporter, image->asLegacyBitmap(&bitmap, modes[i]));
fmalitaea561bf2015-07-09 17:10:31 -0700420 check_legacy_bitmap(reporter, image, bitmap, modes[i]);
reed3c065112015-07-08 12:46:22 -0700421
fmalitaea561bf2015-07-09 17:10:31 -0700422 // Test subsetting to exercise the rowBytes logic.
423 SkBitmap tmp;
424 REPORTER_ASSERT(reporter, bitmap.extractSubset(&tmp, SkIRect::MakeWH(image->width() / 2,
425 image->height() / 2)));
426 SkAutoTUnref<SkImage> subsetImage(SkImage::NewFromBitmap(tmp));
427 REPORTER_ASSERT(reporter, subsetImage);
reed3c065112015-07-08 12:46:22 -0700428
fmalitaea561bf2015-07-09 17:10:31 -0700429 SkBitmap subsetBitmap;
430 REPORTER_ASSERT(reporter, subsetImage->asLegacyBitmap(&subsetBitmap, modes[i]));
431 check_legacy_bitmap(reporter, subsetImage, subsetBitmap, modes[i]);
reed3c065112015-07-08 12:46:22 -0700432 }
433}
434
reed67f2eb42014-12-10 06:54:06 -0800435static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* factory) {
reed@google.com4f7c6152014-02-06 14:11:56 +0000436 static const struct {
437 ImageType fType;
438 bool fPeekShouldSucceed;
reed67f2eb42014-12-10 06:54:06 -0800439 const char* fName;
reed@google.com4f7c6152014-02-06 14:11:56 +0000440 } gRec[] = {
reed67f2eb42014-12-10 06:54:06 -0800441 { kRasterCopy_ImageType, true, "RasterCopy" },
442 { kRasterData_ImageType, true, "RasterData" },
reedde499882015-06-18 13:41:40 -0700443 { kRasterProc_ImageType, true, "RasterProc" },
reed67f2eb42014-12-10 06:54:06 -0800444 { kGpu_ImageType, false, "Gpu" },
445 { kCodec_ImageType, false, "Codec" },
reed@google.com4f7c6152014-02-06 14:11:56 +0000446 };
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000447
reed@google.com4f7c6152014-02-06 14:11:56 +0000448 const SkColor color = SK_ColorRED;
449 const SkPMColor pmcolor = SkPreMultiplyColor(color);
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000450
reed67f2eb42014-12-10 06:54:06 -0800451 GrContext* ctx = NULL;
452#if SK_SUPPORT_GPU
453 ctx = factory->get(GrContextFactory::kNative_GLContextType);
senorblancoc8e93402015-04-21 07:20:36 -0700454 if (NULL == ctx) {
senorblanco84bfd392015-04-21 06:59:17 -0700455 return;
456 }
reed67f2eb42014-12-10 06:54:06 -0800457#endif
458
reedde499882015-06-18 13:41:40 -0700459 ReleaseDataContext releaseCtx;
460 releaseCtx.fReporter = reporter;
461
reed@google.com4f7c6152014-02-06 14:11:56 +0000462 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
463 SkImageInfo info;
464 size_t rowBytes;
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000465
reedde499882015-06-18 13:41:40 -0700466 releaseCtx.fData = NULL;
reedfa5e68e2015-06-29 07:37:01 -0700467 SkAutoTUnref<SkImage> image(create_image(reporter, gRec[i].fType, ctx, color, &releaseCtx));
reed@google.com4f7c6152014-02-06 14:11:56 +0000468 if (!image.get()) {
reed67f2eb42014-12-10 06:54:06 -0800469 SkDebugf("failed to createImage[%d] %s\n", i, gRec[i].fName);
reed@google.com4f7c6152014-02-06 14:11:56 +0000470 continue; // gpu may not be enabled
471 }
reedde499882015-06-18 13:41:40 -0700472 if (kRasterProc_ImageType == gRec[i].fType) {
473 REPORTER_ASSERT(reporter, NULL != releaseCtx.fData); // we are tracking the data
474 } else {
475 REPORTER_ASSERT(reporter, NULL == releaseCtx.fData); // we ignored the context
476 }
477
reed3c065112015-07-08 12:46:22 -0700478 test_legacy_bitmap(reporter, image);
479
reed@google.com4f7c6152014-02-06 14:11:56 +0000480 const void* addr = image->peekPixels(&info, &rowBytes);
bsalomon49f085d2014-09-05 13:34:00 -0700481 bool success = SkToBool(addr);
reed@google.com4f7c6152014-02-06 14:11:56 +0000482 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
483 if (success) {
reede5ea5002014-09-03 11:54:58 -0700484 REPORTER_ASSERT(reporter, 10 == info.width());
485 REPORTER_ASSERT(reporter, 10 == info.height());
486 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType());
487 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() ||
488 kOpaque_SkAlphaType == info.alphaType());
reed@google.com4f7c6152014-02-06 14:11:56 +0000489 REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes);
490 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
491 }
reed96472de2014-12-10 09:53:42 -0800492
493 test_image_readpixels(reporter, image, pmcolor);
reed@google.com4f7c6152014-02-06 14:11:56 +0000494 }
reedde499882015-06-18 13:41:40 -0700495 REPORTER_ASSERT(reporter, NULL == releaseCtx.fData); // we released the data
reed@google.com4f7c6152014-02-06 14:11:56 +0000496}
497
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000498static void test_canvaspeek(skiatest::Reporter* reporter,
499 GrContextFactory* factory) {
500 static const struct {
501 SurfaceType fType;
502 bool fPeekShouldSucceed;
503 } gRec[] = {
504 { kRaster_SurfaceType, true },
505 { kRasterDirect_SurfaceType, true },
506#if SK_SUPPORT_GPU
507 { kGpu_SurfaceType, false },
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000508 { kGpuScratch_SurfaceType, false },
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000509#endif
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000510 };
511
512 const SkColor color = SK_ColorRED;
513 const SkPMColor pmcolor = SkPreMultiplyColor(color);
514
bsalomone904c092014-07-17 10:50:59 -0700515 int cnt;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000516#if SK_SUPPORT_GPU
bsalomone904c092014-07-17 10:50:59 -0700517 cnt = GrContextFactory::kGLContextTypeCnt;
518#else
519 cnt = 1;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000520#endif
521
bsalomone904c092014-07-17 10:50:59 -0700522 for (int i= 0; i < cnt; ++i) {
523 GrContext* context = NULL;
524#if SK_SUPPORT_GPU
525 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
526 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
527 continue;
528 }
529 context = factory->get(glCtxType);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000530
bsalomone904c092014-07-17 10:50:59 -0700531 if (NULL == context) {
532 continue;
533 }
534#endif
535 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
536 SkImageInfo info, requestInfo;
537 size_t rowBytes;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000538
bsalomon74f681d2015-06-23 14:38:48 -0700539 SkAutoTUnref<SkSurface> surface(create_surface(gRec[i].fType, context,
540 kPremul_SkAlphaType, &requestInfo));
bsalomone904c092014-07-17 10:50:59 -0700541 surface->getCanvas()->clear(color);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000542
bsalomone904c092014-07-17 10:50:59 -0700543 const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes);
bsalomon49f085d2014-09-05 13:34:00 -0700544 bool success = SkToBool(addr);
bsalomone904c092014-07-17 10:50:59 -0700545 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000546
bsalomone904c092014-07-17 10:50:59 -0700547 SkImageInfo info2;
548 size_t rb2;
549 const void* addr2 = surface->peekPixels(&info2, &rb2);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000550
bsalomone904c092014-07-17 10:50:59 -0700551 if (success) {
552 REPORTER_ASSERT(reporter, requestInfo == info);
553 REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes);
554 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
555
556 REPORTER_ASSERT(reporter, addr2 == addr);
557 REPORTER_ASSERT(reporter, info2 == info);
558 REPORTER_ASSERT(reporter, rb2 == rowBytes);
559 } else {
560 REPORTER_ASSERT(reporter, NULL == addr2);
561 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000562 }
563 }
564}
565
reed41e010c2015-06-09 12:16:53 -0700566// For compatibility with clients that still call accessBitmap(), we need to ensure that we bump
567// the bitmap's genID when we draw to it, else they won't know it has new values. When they are
568// exclusively using surface/image, and we can hide accessBitmap from device, we can remove this
569// test.
570static void test_accessPixels(skiatest::Reporter* reporter, GrContextFactory* factory) {
571 static const struct {
572 SurfaceType fType;
573 bool fPeekShouldSucceed;
574 } gRec[] = {
575 { kRaster_SurfaceType, true },
576 { kRasterDirect_SurfaceType, true },
577#if SK_SUPPORT_GPU
578 { kGpu_SurfaceType, false },
579 { kGpuScratch_SurfaceType, false },
580#endif
581 };
582
583 int cnt;
584#if SK_SUPPORT_GPU
585 cnt = GrContextFactory::kGLContextTypeCnt;
586#else
587 cnt = 1;
588#endif
589
590 for (int i= 0; i < cnt; ++i) {
591 GrContext* context = NULL;
592#if SK_SUPPORT_GPU
593 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
594 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
595 continue;
596 }
597 context = factory->get(glCtxType);
598
599 if (NULL == context) {
600 continue;
601 }
602#endif
603 for (size_t j = 0; j < SK_ARRAY_COUNT(gRec); ++j) {
604 SkImageInfo info, requestInfo;
605
bsalomon74f681d2015-06-23 14:38:48 -0700606 SkAutoTUnref<SkSurface> surface(create_surface(gRec[j].fType, context,
607 kPremul_SkAlphaType, &requestInfo));
reed41e010c2015-06-09 12:16:53 -0700608 SkCanvas* canvas = surface->getCanvas();
609 canvas->clear(0);
610
611 SkBaseDevice* device = canvas->getDevice_just_for_deprecated_compatibility_testing();
612 SkBitmap bm = device->accessBitmap(false);
613 uint32_t genID0 = bm.getGenerationID();
614 // Now we draw something, which needs to "dirty" the genID (sorta like copy-on-write)
615 canvas->drawColor(SK_ColorBLUE);
616 // Now check that we get a different genID
617 uint32_t genID1 = bm.getGenerationID();
618 REPORTER_ASSERT(reporter, genID0 != genID1);
619 }
620 }
621}
622
bsalomon74f681d2015-06-23 14:38:48 -0700623static void test_snap_alphatype(skiatest::Reporter* reporter, GrContextFactory* factory) {
624 GrContext* context = NULL;
625#if SK_SUPPORT_GPU
626 context = factory->get(GrContextFactory::kNative_GLContextType);
627 if (NULL == context) {
628 return;
629 }
630#endif
631 for (int opaque = 0; opaque < 2; ++opaque) {
632 SkAlphaType atype = SkToBool(opaque) ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
633 for (int st = 0; st < kSurfaceTypeCnt; ++st) {
634 SurfaceType stype = (SurfaceType)st;
635 SkAutoTUnref<SkSurface> surface(create_surface(stype, context, atype));
636 REPORTER_ASSERT(reporter, surface);
637 if (surface) {
638 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
639 REPORTER_ASSERT(reporter, image);
640 if (image) {
641 REPORTER_ASSERT(reporter, image->isOpaque() == SkToBool(opaque));
642 }
643 }
644 }
645 }
646}
647
junov@chromium.org995beb62013-03-28 13:49:22 +0000648static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType,
649 GrContext* context) {
650 // Verify that the right canvas commands trigger a copy on write
bsalomon74f681d2015-06-23 14:38:48 -0700651 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.org995beb62013-03-28 13:49:22 +0000652 SkAutoTUnref<SkSurface> aur_surface(surface);
653 SkCanvas* canvas = surface->getCanvas();
654
655 const SkRect testRect =
656 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
657 SkIntToScalar(4), SkIntToScalar(5));
junov@chromium.org995beb62013-03-28 13:49:22 +0000658 SkPath testPath;
659 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
660 SkIntToScalar(2), SkIntToScalar(1)));
661
662 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1);
663
664 SkRegion testRegion;
665 testRegion.setRect(testIRect);
666
667
668 const SkColor testColor = 0x01020304;
669 const SkPaint testPaint;
670 const SkPoint testPoints[3] = {
671 {SkIntToScalar(0), SkIntToScalar(0)},
672 {SkIntToScalar(2), SkIntToScalar(1)},
673 {SkIntToScalar(0), SkIntToScalar(2)}
674 };
675 const size_t testPointCount = 3;
676
677 SkBitmap testBitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000678 testBitmap.allocN32Pixels(10, 10);
robertphillips@google.comd1ce77d2013-10-09 12:51:09 +0000679 testBitmap.eraseColor(0);
junov@chromium.org995beb62013-03-28 13:49:22 +0000680
681 SkRRect testRRect;
682 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1);
683
684 SkString testText("Hello World");
685 const SkPoint testPoints2[] = {
686 { SkIntToScalar(0), SkIntToScalar(1) },
687 { SkIntToScalar(1), SkIntToScalar(1) },
688 { SkIntToScalar(2), SkIntToScalar(1) },
689 { SkIntToScalar(3), SkIntToScalar(1) },
690 { SkIntToScalar(4), SkIntToScalar(1) },
691 { SkIntToScalar(5), SkIntToScalar(1) },
692 { SkIntToScalar(6), SkIntToScalar(1) },
693 { SkIntToScalar(7), SkIntToScalar(1) },
694 { SkIntToScalar(8), SkIntToScalar(1) },
695 { SkIntToScalar(9), SkIntToScalar(1) },
696 { SkIntToScalar(10), SkIntToScalar(1) },
697 };
698
699#define EXPECT_COPY_ON_WRITE(command) \
700 { \
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000701 SkImage* imageBefore = surface->newImageSnapshot(); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000702 SkAutoTUnref<SkImage> aur_before(imageBefore); \
703 canvas-> command ; \
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000704 SkImage* imageAfter = surface->newImageSnapshot(); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000705 SkAutoTUnref<SkImage> aur_after(imageAfter); \
706 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \
707 }
708
709 EXPECT_COPY_ON_WRITE(clear(testColor))
710 EXPECT_COPY_ON_WRITE(drawPaint(testPaint))
711 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \
712 testPaint))
713 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint))
714 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint))
715 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint))
716 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint))
717 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0))
718 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect))
junov@chromium.org995beb62013-03-28 13:49:22 +0000719 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL))
720 EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL))
721 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint))
722 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \
723 testPaint))
724 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \
725 testPaint))
726}
727
junov@chromium.orgaf058352013-04-03 15:03:26 +0000728static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter,
729 SurfaceType surfaceType,
730 GrContext* context) {
731 // This test succeeds by not triggering an assertion.
732 // The test verifies that the surface remains writable (usable) after
733 // acquiring and releasing a snapshot without triggering a copy on write.
bsalomon74f681d2015-06-23 14:38:48 -0700734 SkAutoTUnref<SkSurface> surface(create_surface(surfaceType, context));
junov@chromium.orgaf058352013-04-03 15:03:26 +0000735 SkCanvas* canvas = surface->getCanvas();
736 canvas->clear(1);
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000737 surface->newImageSnapshot()->unref(); // Create and destroy SkImage
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000738 canvas->clear(2); // Must not assert internally
junov@chromium.org995beb62013-03-28 13:49:22 +0000739}
junov@chromium.orgda904742013-05-01 22:38:16 +0000740
junov@chromium.orgb516a412013-05-01 22:49:59 +0000741#if SK_SUPPORT_GPU
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000742static void Test_crbug263329(skiatest::Reporter* reporter,
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000743 SurfaceType surfaceType,
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000744 GrContext* context) {
745 // This is a regression test for crbug.com/263329
746 // Bug was caused by onCopyOnWrite releasing the old surface texture
747 // back to the scratch texture pool even though the texture is used
748 // by and active SkImage_Gpu.
bsalomon74f681d2015-06-23 14:38:48 -0700749 SkAutoTUnref<SkSurface> surface1(create_surface(surfaceType, context));
750 SkAutoTUnref<SkSurface> surface2(create_surface(surfaceType, context));
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000751 SkCanvas* canvas1 = surface1->getCanvas();
752 SkCanvas* canvas2 = surface2->getCanvas();
753 canvas1->clear(1);
754 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot());
755 // Trigger copy on write, new backing is a scratch texture
756 canvas1->clear(2);
757 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot());
758 // Trigger copy on write, old backing should not be returned to scratch
759 // pool because it is held by image2
760 canvas1->clear(3);
761
762 canvas2->clear(4);
763 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot());
764 // Trigger copy on write on surface2. The new backing store should not
765 // be recycling a texture that is held by an existing image.
766 canvas2->clear(5);
767 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot());
bsalomon55812362015-06-10 08:49:28 -0700768 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image3)->getTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000769 // The following assertion checks crbug.com/263329
bsalomon55812362015-06-10 08:49:28 -0700770 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image2)->getTexture());
771 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image1)->getTexture());
772 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image2)->getTexture());
773 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image1)->getTexture());
774 REPORTER_ASSERT(reporter, as_IB(image2)->getTexture() != as_IB(image1)->getTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000775}
776
junov@chromium.orgda904742013-05-01 22:38:16 +0000777static void TestGetTexture(skiatest::Reporter* reporter,
778 SurfaceType surfaceType,
779 GrContext* context) {
bsalomon74f681d2015-06-23 14:38:48 -0700780 SkAutoTUnref<SkSurface> surface(create_surface(surfaceType, context));
junov@chromium.orgda904742013-05-01 22:38:16 +0000781 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
bsalomon55812362015-06-10 08:49:28 -0700782 GrTexture* texture = as_IB(image)->getTexture();
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000783 if (surfaceType == kGpu_SurfaceType || surfaceType == kGpuScratch_SurfaceType) {
bsalomon49f085d2014-09-05 13:34:00 -0700784 REPORTER_ASSERT(reporter, texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000785 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle());
786 } else {
787 REPORTER_ASSERT(reporter, NULL == texture);
788 }
789 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
bsalomon55812362015-06-10 08:49:28 -0700790 REPORTER_ASSERT(reporter, as_IB(image)->getTexture() == texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000791}
bsalomoneaaaf0b2015-01-23 08:08:04 -0800792
bsalomon3582d3e2015-02-13 14:20:05 -0800793#include "GrGpuResourcePriv.h"
bsalomoneaaaf0b2015-01-23 08:08:04 -0800794#include "SkGpuDevice.h"
795#include "SkImage_Gpu.h"
796#include "SkSurface_Gpu.h"
797
798SkSurface::Budgeted is_budgeted(SkSurface* surf) {
bsalomon3582d3e2015-02-13 14:20:05 -0800799 return ((SkSurface_Gpu*)surf)->getDevice()->accessRenderTarget()->resourcePriv().isBudgeted() ?
bsalomoneaaaf0b2015-01-23 08:08:04 -0800800 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
801}
802
803SkSurface::Budgeted is_budgeted(SkImage* image) {
bsalomon3582d3e2015-02-13 14:20:05 -0800804 return ((SkImage_Gpu*)image)->getTexture()->resourcePriv().isBudgeted() ?
bsalomoneaaaf0b2015-01-23 08:08:04 -0800805 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
806}
807
808static void test_surface_budget(skiatest::Reporter* reporter, GrContext* context) {
809 SkImageInfo info = SkImageInfo::MakeN32Premul(8,8);
810 for (int i = 0; i < 2; ++i) {
811 SkSurface::Budgeted sbudgeted = i ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
812 for (int j = 0; j < 2; ++j) {
813 SkSurface::Budgeted ibudgeted = j ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
814 SkAutoTUnref<SkSurface>
815 surface(SkSurface::NewRenderTarget(context, sbudgeted, info, 0));
816 SkASSERT(surface);
817 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
818
mtklein31ff2982015-01-24 11:27:27 -0800819 SkAutoTUnref<SkImage> image(surface->newImageSnapshot(ibudgeted));
bsalomoneaaaf0b2015-01-23 08:08:04 -0800820
821 // Initially the image shares a texture with the surface, and the surface decides
822 // whether it is budgeted or not.
823 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
824 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(image));
825
826 // Now trigger copy-on-write
827 surface->getCanvas()->clear(SK_ColorBLUE);
828
829 // They don't share a texture anymore. They should each have made their own budget
830 // decision.
831 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
832 REPORTER_ASSERT(reporter, ibudgeted == is_budgeted(image));
833 }
834 }
835}
836
junov@chromium.orgb516a412013-05-01 22:49:59 +0000837#endif
junov@chromium.orgda904742013-05-01 22:38:16 +0000838
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000839static void TestSurfaceNoCanvas(skiatest::Reporter* reporter,
840 SurfaceType surfaceType,
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000841 GrContext* context,
842 SkSurface::ContentChangeMode mode) {
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000843 // Verifies the robustness of SkSurface for handling use cases where calls
844 // are made before a canvas is created.
845 {
846 // Test passes by not asserting
bsalomon74f681d2015-06-23 14:38:48 -0700847 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000848 SkAutoTUnref<SkSurface> aur_surface(surface);
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000849 surface->notifyContentWillChange(mode);
robertphillips@google.com03087072013-10-02 16:42:21 +0000850 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000851 }
852 {
bsalomon74f681d2015-06-23 14:38:48 -0700853 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000854 SkAutoTUnref<SkSurface> aur_surface(surface);
855 SkImage* image1 = surface->newImageSnapshot();
856 SkAutoTUnref<SkImage> aur_image1(image1);
robertphillips@google.com03087072013-10-02 16:42:21 +0000857 SkDEBUGCODE(image1->validate();)
858 SkDEBUGCODE(surface->validate();)
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000859 surface->notifyContentWillChange(mode);
robertphillips@google.com03087072013-10-02 16:42:21 +0000860 SkDEBUGCODE(image1->validate();)
861 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000862 SkImage* image2 = surface->newImageSnapshot();
863 SkAutoTUnref<SkImage> aur_image2(image2);
robertphillips@google.com03087072013-10-02 16:42:21 +0000864 SkDEBUGCODE(image2->validate();)
865 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000866 REPORTER_ASSERT(reporter, image1 != image2);
867 }
skia.committer@gmail.com45fb8b62013-04-17 07:00:56 +0000868
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000869}
junov@chromium.org995beb62013-03-28 13:49:22 +0000870
tfarina@chromium.org4ee16bf2014-01-10 22:08:27 +0000871DEF_GPUTEST(Surface, reporter, factory) {
reed@google.com999da9c2014-02-06 13:43:07 +0000872 test_image(reporter);
873
junov@chromium.orgaf058352013-04-03 15:03:26 +0000874 TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL);
junov@chromium.orgaf058352013-04-03 15:03:26 +0000875 TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL);
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000876 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode);
877 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000878
reedb2497c22014-12-31 12:31:43 -0800879 test_empty_image(reporter);
880 test_empty_surface(reporter, NULL);
881
reed67f2eb42014-12-10 06:54:06 -0800882 test_imagepeek(reporter, factory);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000883 test_canvaspeek(reporter, factory);
884
reed41e010c2015-06-09 12:16:53 -0700885 test_accessPixels(reporter, factory);
886
bsalomon74f681d2015-06-23 14:38:48 -0700887 test_snap_alphatype(reporter, factory);
888
junov@chromium.orgb516a412013-05-01 22:49:59 +0000889#if SK_SUPPORT_GPU
junov@chromium.orgda904742013-05-01 22:38:16 +0000890 TestGetTexture(reporter, kRaster_SurfaceType, NULL);
bsalomon49f085d2014-09-05 13:34:00 -0700891 if (factory) {
bsalomone904c092014-07-17 10:50:59 -0700892 for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
893 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
894 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
895 continue;
896 }
897 GrContext* context = factory->get(glCtxType);
bsalomon49f085d2014-09-05 13:34:00 -0700898 if (context) {
bsalomone904c092014-07-17 10:50:59 -0700899 Test_crbug263329(reporter, kGpu_SurfaceType, context);
900 Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
901 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
902 TestSurfaceCopyOnWrite(reporter, kGpuScratch_SurfaceType, context);
903 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context);
904 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpuScratch_SurfaceType, context);
905 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
906 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
907 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
908 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
909 TestGetTexture(reporter, kGpu_SurfaceType, context);
910 TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
reedb2497c22014-12-31 12:31:43 -0800911 test_empty_surface(reporter, context);
bsalomoneaaaf0b2015-01-23 08:08:04 -0800912 test_surface_budget(reporter, context);
joshualitt81793412015-07-08 12:54:04 -0700913 test_wrapped_texture_surface(reporter, context);
bsalomone904c092014-07-17 10:50:59 -0700914 }
robertphillips@google.com3bddb382013-11-12 13:51:03 +0000915 }
junov@chromium.orgaf058352013-04-03 15:03:26 +0000916 }
junov@chromium.org995beb62013-03-28 13:49:22 +0000917#endif
918}
reed8b26b992015-05-07 15:36:17 -0700919
920#if SK_SUPPORT_GPU
reedde499882015-06-18 13:41:40 -0700921
922struct ReleaseTextureContext {
923 ReleaseTextureContext(skiatest::Reporter* reporter) {
924 fReporter = reporter;
925 fIsReleased = false;
926 }
927
928 skiatest::Reporter* fReporter;
929 bool fIsReleased;
930
931 void doRelease() {
932 REPORTER_ASSERT(fReporter, false == fIsReleased);
933 fIsReleased = true;
934 }
935
936 static void ReleaseProc(void* context) {
937 ((ReleaseTextureContext*)context)->doRelease();
938 }
939};
940
941static SkImage* make_desc_image(GrContext* ctx, int w, int h, GrBackendObject texID,
942 ReleaseTextureContext* releaseContext) {
reed8b26b992015-05-07 15:36:17 -0700943 GrBackendTextureDesc desc;
944 desc.fConfig = kSkia8888_GrPixelConfig;
945 // need to be a rendertarget for now...
946 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
947 desc.fWidth = w;
948 desc.fHeight = h;
949 desc.fSampleCnt = 0;
950 desc.fTextureHandle = texID;
reedde499882015-06-18 13:41:40 -0700951 return releaseContext
952 ? SkImage::NewFromTexture(ctx, desc, kPremul_SkAlphaType,
953 ReleaseTextureContext::ReleaseProc, releaseContext)
954 : SkImage::NewFromTextureCopy(ctx, desc, kPremul_SkAlphaType);
reed8b26b992015-05-07 15:36:17 -0700955}
956
957static void test_image_color(skiatest::Reporter* reporter, SkImage* image, SkPMColor expected) {
958 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
959 SkPMColor pixel;
960 REPORTER_ASSERT(reporter, image->readPixels(info, &pixel, sizeof(pixel), 0, 0));
961 REPORTER_ASSERT(reporter, pixel == expected);
962}
963
964DEF_GPUTEST(SkImage_NewFromTexture, reporter, factory) {
965 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
966 if (!ctx) {
967 REPORTER_ASSERT(reporter, false);
968 return;
969 }
970 GrTextureProvider* provider = ctx->textureProvider();
971
972 const int w = 10;
973 const int h = 10;
974 SkPMColor storage[w * h];
975 const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED);
976 sk_memset32(storage, expected0, w * h);
977
978 GrSurfaceDesc desc;
979 desc.fFlags = kRenderTarget_GrSurfaceFlag; // needs to be a rendertarget for readpixels();
980 desc.fOrigin = kDefault_GrSurfaceOrigin;
981 desc.fWidth = w;
982 desc.fHeight = h;
983 desc.fConfig = kSkia8888_GrPixelConfig;
984 desc.fSampleCnt = 0;
985
986 SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, false, storage, w * 4));
987 if (!tex) {
988 REPORTER_ASSERT(reporter, false);
989 return;
990 }
reedde499882015-06-18 13:41:40 -0700991
reed8b26b992015-05-07 15:36:17 -0700992 GrBackendObject srcTex = tex->getTextureHandle();
reedde499882015-06-18 13:41:40 -0700993 ReleaseTextureContext releaseCtx(reporter);
994
995 SkAutoTUnref<SkImage> refImg(make_desc_image(ctx, w, h, srcTex, &releaseCtx));
996 SkAutoTUnref<SkImage> cpyImg(make_desc_image(ctx, w, h, srcTex, NULL));
reed8b26b992015-05-07 15:36:17 -0700997
998 test_image_color(reporter, refImg, expected0);
999 test_image_color(reporter, cpyImg, expected0);
1000
1001 // Now lets jam new colors into our "external" texture, and see if the images notice
1002 const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE);
1003 sk_memset32(storage, expected1, w * h);
1004 tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp);
1005
1006 // We expect the ref'd image to see the new color, but cpy'd one should still see the old color
1007 test_image_color(reporter, refImg, expected1);
1008 test_image_color(reporter, cpyImg, expected0);
reedde499882015-06-18 13:41:40 -07001009
1010 // Now exercise the release proc
1011 REPORTER_ASSERT(reporter, !releaseCtx.fIsReleased);
1012 refImg.reset(NULL); // force a release of the image
1013 REPORTER_ASSERT(reporter, releaseCtx.fIsReleased);
reed8b26b992015-05-07 15:36:17 -07001014}
1015#endif