blob: d78498f6b9142e01f7608327bb6ce7f36d742f55 [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
bsalomond3e259a2015-06-30 12:04:40 -0700105static void test_wrapped_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
bsalomond3e259a2015-06-30 12:04:40 -0700123 for (int useFBO = 0; useFBO < 2; ++useFBO) {
124 // Test the wrapped factory for SkSurface by creating a texture using GL and then wrap it in
125 // a SkSurface.
126 GrGLuint texID;
127 static const int kW = 100;
128 static const int kH = 100;
129 static const uint32_t kOrigColor = 0xFFAABBCC;
130 SkAutoTArray<uint32_t> pixels(kW * kH);
131 sk_memset32(pixels.get(), kOrigColor, kW * kH);
132 GR_GL_CALL(gl, GenTextures(1, &texID));
133 GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE0));
134 GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
135 GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texID));
136 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER,
137 GR_GL_NEAREST));
138 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER,
139 GR_GL_NEAREST));
140 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S,
141 GR_GL_CLAMP_TO_EDGE));
142 GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T,
143 GR_GL_CLAMP_TO_EDGE));
144 GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RGBA, kW, kH, 0, GR_GL_RGBA,
145 GR_GL_UNSIGNED_BYTE,
146 pixels.get()));
bsalomone4579ad2015-04-08 08:38:40 -0700147
bsalomond3e259a2015-06-30 12:04:40 -0700148 SkAutoTUnref<SkSurface> surface;
149 GrGLuint fboID = 0;
150 if (useFBO) {
151 GR_GL_CALL(gl, GenFramebuffers(1, &fboID));
152 GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, fboID));
153 GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
154 GR_GL_TEXTURE_2D, texID, 0));
155 GrBackendRenderTargetDesc wrappedDesc;
156 wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
157 wrappedDesc.fWidth = kW;
158 wrappedDesc.fHeight = kH;
159 wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
160 wrappedDesc.fSampleCnt = 0;
161 wrappedDesc.fRenderTargetHandle = fboID;
162 wrappedDesc.fStencilBits = 0;
bsalomone4579ad2015-04-08 08:38:40 -0700163
bsalomond3e259a2015-06-30 12:04:40 -0700164 ctx->resetContext();
165 surface.reset(SkSurface::NewFromBackendRenderTarget(ctx, wrappedDesc, NULL));
166 } else {
167 GrBackendTextureDesc wrappedDesc;
168 wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
169 wrappedDesc.fWidth = kW;
170 wrappedDesc.fHeight = kH;
171 wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
172 wrappedDesc.fSampleCnt = 0;
173 wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
174 wrappedDesc.fTextureHandle = texID;
175
176 ctx->resetContext();
177 surface.reset(SkSurface::NewFromBackendTexture(ctx, wrappedDesc, NULL));
178 }
179 REPORTER_ASSERT(reporter, surface);
180 if (surface) {
181 // Validate that we can draw to the canvas and that the original texture color is
182 // preserved in pixels that aren't rendered to via the surface.
183 SkPaint paint;
184 static const SkColor kRectColor = ~kOrigColor | 0xFF000000;
185 paint.setColor(kRectColor);
186 surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2),
187 paint);
188 SkImageInfo readInfo = SkImageInfo::MakeN32Premul(kW, kH);
189 surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0);
190 bool stop = false;
191 SkPMColor origColorPM = SkPackARGB32((kOrigColor >> 24 & 0xFF),
192 (kOrigColor >> 0 & 0xFF),
193 (kOrigColor >> 8 & 0xFF),
194 (kOrigColor >> 16 & 0xFF));
195 SkPMColor rectColorPM = SkPackARGB32((kRectColor >> 24 & 0xFF),
196 (kRectColor >> 16 & 0xFF),
197 (kRectColor >> 8 & 0xFF),
198 (kRectColor >> 0 & 0xFF));
199 for (int y = 0; y < kH/2 && !stop; ++y) {
200 for (int x = 0; x < kW && !stop; ++x) {
201 REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]);
202 if (rectColorPM != pixels[x + y * kW]) {
203 stop = true;
204 }
205 }
206 }
207 stop = false;
208 for (int y = kH/2; y < kH && !stop; ++y) {
209 for (int x = 0; x < kW && !stop; ++x) {
210 REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]);
211 if (origColorPM != pixels[x + y * kW]) {
212 stop = true;
213 }
bsalomon7a617932015-06-16 08:07:16 -0700214 }
215 }
216 }
bsalomond3e259a2015-06-30 12:04:40 -0700217 if (texID) {
218 GR_GL_CALL(gl, DeleteTextures(1, &texID));
bsalomon7a617932015-06-16 08:07:16 -0700219 }
bsalomond3e259a2015-06-30 12:04:40 -0700220 if (fboID) {
221 GR_GL_CALL(gl, DeleteFramebuffers(1, &fboID));
222 }
223
bsalomon7a617932015-06-16 08:07:16 -0700224 }
bsalomone4579ad2015-04-08 08:38:40 -0700225}
226#endif
227
228
reed@google.com999da9c2014-02-06 13:43:07 +0000229static void test_image(skiatest::Reporter* reporter) {
230 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
231 size_t rowBytes = info.minRowBytes();
232 size_t size = info.getSafeSize(rowBytes);
reed9594da12014-09-12 12:12:27 -0700233 SkData* data = SkData::NewUninitialized(size);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000234
mtkleinbbb61d72014-11-24 13:09:39 -0800235 REPORTER_ASSERT(reporter, data->unique());
reed@google.com999da9c2014-02-06 13:43:07 +0000236 SkImage* image = SkImage::NewRasterData(info, data, rowBytes);
mtkleinbbb61d72014-11-24 13:09:39 -0800237 REPORTER_ASSERT(reporter, !data->unique());
reed@google.com999da9c2014-02-06 13:43:07 +0000238 image->unref();
mtkleinbbb61d72014-11-24 13:09:39 -0800239 REPORTER_ASSERT(reporter, data->unique());
reed@google.com999da9c2014-02-06 13:43:07 +0000240 data->unref();
241}
242
reedde499882015-06-18 13:41:40 -0700243// Want to ensure that our Release is called when the owning image is destroyed
244struct ReleaseDataContext {
245 skiatest::Reporter* fReporter;
246 SkData* fData;
247
248 static void Release(const void* pixels, void* context) {
249 ReleaseDataContext* state = (ReleaseDataContext*)context;
250 REPORTER_ASSERT(state->fReporter, state->fData);
251 state->fData->unref();
252 state->fData = NULL;
253 }
254};
255
reed09b2c932015-06-29 14:09:41 -0700256// May we (soon) eliminate the need to keep testing this, by hiding the bloody device!
257#include "SkDevice.h"
258static uint32_t get_legacy_gen_id(SkSurface* surf) {
259 SkBaseDevice* device = surf->getCanvas()->getDevice_just_for_deprecated_compatibility_testing();
260 return device->accessBitmap(false).getGenerationID();
261}
262
reeddca20ce2015-07-03 10:43:43 -0700263/*
264 * Test legacy behavor of bumping the surface's device's bitmap's genID when we access its
265 * texture handle for writing.
266 *
267 * Note: this needs to be tested separately from checking newImageSnapshot, as calling that
268 * can also incidentally bump the genID (when a new backing surface is created).
269 */
270static void test_texture_handle_genID(skiatest::Reporter* reporter, SkSurface* surf) {
271 const uint32_t gen0 = get_legacy_gen_id(surf);
272 surf->getTextureHandle(SkSurface::kFlushRead_TextureHandleAccess);
273 const uint32_t gen1 = get_legacy_gen_id(surf);
274 REPORTER_ASSERT(reporter, gen0 == gen1);
275
276 surf->getTextureHandle(SkSurface::kFlushWrite_TextureHandleAccess);
277 const uint32_t gen2 = get_legacy_gen_id(surf);
278 REPORTER_ASSERT(reporter, gen0 != gen2);
279
280 surf->getTextureHandle(SkSurface::kDiscardWrite_TextureHandleAccess);
281 const uint32_t gen3 = get_legacy_gen_id(surf);
282 REPORTER_ASSERT(reporter, gen0 != gen3);
283 REPORTER_ASSERT(reporter, gen2 != gen3);
284}
285
reedfa5e68e2015-06-29 07:37:01 -0700286static void test_texture_handle(skiatest::Reporter* reporter, SkSurface* surf) {
287 SkAutoTUnref<SkImage> image0(surf->newImageSnapshot());
288 GrBackendObject obj = surf->getTextureHandle(SkSurface::kFlushRead_TextureHandleAccess);
289 REPORTER_ASSERT(reporter, obj != 0);
290 SkAutoTUnref<SkImage> image1(surf->newImageSnapshot());
291 // just read access should not affect the snapshot
292 REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID());
293
294 obj = surf->getTextureHandle(SkSurface::kFlushWrite_TextureHandleAccess);
295 REPORTER_ASSERT(reporter, obj != 0);
296 SkAutoTUnref<SkImage> image2(surf->newImageSnapshot());
297 // expect a new image, since we claimed we would write
298 REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID());
299
300 obj = surf->getTextureHandle(SkSurface::kDiscardWrite_TextureHandleAccess);
301 REPORTER_ASSERT(reporter, obj != 0);
302 SkAutoTUnref<SkImage> image3(surf->newImageSnapshot());
303 // expect a new(er) image, since we claimed we would write
304 REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID());
305 REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID());
306}
307
308static SkImage* create_image(skiatest::Reporter* reporter,
309 ImageType imageType, GrContext* context, SkColor color,
bsalomon74f681d2015-06-23 14:38:48 -0700310 ReleaseDataContext* releaseContext) {
reed@google.com4f7c6152014-02-06 14:11:56 +0000311 const SkPMColor pmcolor = SkPreMultiplyColor(color);
312 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
313 const size_t rowBytes = info.minRowBytes();
reede5ea5002014-09-03 11:54:58 -0700314 const size_t size = rowBytes * info.height();
reed@google.com4f7c6152014-02-06 14:11:56 +0000315
reed9594da12014-09-12 12:12:27 -0700316 SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
317 void* addr = data->writable_data();
reed@google.com4f7c6152014-02-06 14:11:56 +0000318 sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2));
reed@google.com4f7c6152014-02-06 14:11:56 +0000319
320 switch (imageType) {
321 case kRasterCopy_ImageType:
322 return SkImage::NewRasterCopy(info, addr, rowBytes);
323 case kRasterData_ImageType:
324 return SkImage::NewRasterData(info, data, rowBytes);
reedde499882015-06-18 13:41:40 -0700325 case kRasterProc_ImageType:
326 SkASSERT(releaseContext);
327 releaseContext->fData = SkRef(data.get());
328 return SkImage::NewFromRaster(info, addr, rowBytes,
329 ReleaseDataContext::Release, releaseContext);
reed67f2eb42014-12-10 06:54:06 -0800330 case kGpu_ImageType: {
bsalomonafe30052015-01-16 07:32:33 -0800331 SkAutoTUnref<SkSurface> surf(
332 SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0));
reed67f2eb42014-12-10 06:54:06 -0800333 surf->getCanvas()->clear(color);
reedfa5e68e2015-06-29 07:37:01 -0700334 // test our backing texture while were here...
reeddca20ce2015-07-03 10:43:43 -0700335 test_texture_handle_genID(reporter, surf);
reedfa5e68e2015-06-29 07:37:01 -0700336 test_texture_handle(reporter, surf);
337 // redraw so our returned image looks as expected.
338 surf->getCanvas()->clear(color);
reed67f2eb42014-12-10 06:54:06 -0800339 return surf->newImageSnapshot();
340 }
reed@google.com4f7c6152014-02-06 14:11:56 +0000341 case kCodec_ImageType: {
342 SkBitmap bitmap;
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +0000343 bitmap.installPixels(info, addr, rowBytes);
reed@google.com4f7c6152014-02-06 14:11:56 +0000344 SkAutoTUnref<SkData> src(
reed67f2eb42014-12-10 06:54:06 -0800345 SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100));
reed871872f2015-06-22 12:48:26 -0700346 return SkImage::NewFromEncoded(src);
reed@google.com4f7c6152014-02-06 14:11:56 +0000347 }
348 }
349 SkASSERT(false);
350 return NULL;
351}
352
reed96472de2014-12-10 09:53:42 -0800353static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) {
354 sk_memset32(pixels, color, count);
355}
356static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) {
357 for (int i = 0; i < count; ++i) {
358 if (pixels[i] != expected) {
359 return false;
360 }
361 }
362 return true;
363}
364
365static void test_image_readpixels(skiatest::Reporter* reporter, SkImage* image,
366 SkPMColor expected) {
367 const SkPMColor notExpected = ~expected;
368
369 const int w = 2, h = 2;
370 const size_t rowBytes = w * sizeof(SkPMColor);
371 SkPMColor pixels[w*h];
372
373 SkImageInfo info;
374
375 info = SkImageInfo::MakeUnknown(w, h);
376 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0));
377
378 // out-of-bounds should fail
379 info = SkImageInfo::MakeN32Premul(w, h);
380 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0));
381 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h));
382 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0));
383 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height()));
384
385 // top-left should succeed
386 set_pixels(pixels, w*h, notExpected);
387 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0));
388 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
389
390 // bottom-right should succeed
391 set_pixels(pixels, w*h, notExpected);
392 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
393 image->width() - w, image->height() - h));
394 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
395
396 // partial top-left should succeed
397 set_pixels(pixels, w*h, notExpected);
398 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1));
399 REPORTER_ASSERT(reporter, pixels[3] == expected);
400 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected));
401
402 // partial bottom-right should succeed
403 set_pixels(pixels, w*h, notExpected);
404 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
405 image->width() - 1, image->height() - 1));
406 REPORTER_ASSERT(reporter, pixels[0] == expected);
407 REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected));
408}
409
reed67f2eb42014-12-10 06:54:06 -0800410static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* factory) {
reed@google.com4f7c6152014-02-06 14:11:56 +0000411 static const struct {
412 ImageType fType;
413 bool fPeekShouldSucceed;
reed67f2eb42014-12-10 06:54:06 -0800414 const char* fName;
reed@google.com4f7c6152014-02-06 14:11:56 +0000415 } gRec[] = {
reed67f2eb42014-12-10 06:54:06 -0800416 { kRasterCopy_ImageType, true, "RasterCopy" },
417 { kRasterData_ImageType, true, "RasterData" },
reedde499882015-06-18 13:41:40 -0700418 { kRasterProc_ImageType, true, "RasterProc" },
reed67f2eb42014-12-10 06:54:06 -0800419 { kGpu_ImageType, false, "Gpu" },
420 { kCodec_ImageType, false, "Codec" },
reed@google.com4f7c6152014-02-06 14:11:56 +0000421 };
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000422
reed@google.com4f7c6152014-02-06 14:11:56 +0000423 const SkColor color = SK_ColorRED;
424 const SkPMColor pmcolor = SkPreMultiplyColor(color);
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000425
reed67f2eb42014-12-10 06:54:06 -0800426 GrContext* ctx = NULL;
427#if SK_SUPPORT_GPU
428 ctx = factory->get(GrContextFactory::kNative_GLContextType);
senorblancoc8e93402015-04-21 07:20:36 -0700429 if (NULL == ctx) {
senorblanco84bfd392015-04-21 06:59:17 -0700430 return;
431 }
reed67f2eb42014-12-10 06:54:06 -0800432#endif
433
reedde499882015-06-18 13:41:40 -0700434 ReleaseDataContext releaseCtx;
435 releaseCtx.fReporter = reporter;
436
reed@google.com4f7c6152014-02-06 14:11:56 +0000437 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
438 SkImageInfo info;
439 size_t rowBytes;
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000440
reedde499882015-06-18 13:41:40 -0700441 releaseCtx.fData = NULL;
reedfa5e68e2015-06-29 07:37:01 -0700442 SkAutoTUnref<SkImage> image(create_image(reporter, gRec[i].fType, ctx, color, &releaseCtx));
reed@google.com4f7c6152014-02-06 14:11:56 +0000443 if (!image.get()) {
reed67f2eb42014-12-10 06:54:06 -0800444 SkDebugf("failed to createImage[%d] %s\n", i, gRec[i].fName);
reed@google.com4f7c6152014-02-06 14:11:56 +0000445 continue; // gpu may not be enabled
446 }
reedde499882015-06-18 13:41:40 -0700447 if (kRasterProc_ImageType == gRec[i].fType) {
448 REPORTER_ASSERT(reporter, NULL != releaseCtx.fData); // we are tracking the data
449 } else {
450 REPORTER_ASSERT(reporter, NULL == releaseCtx.fData); // we ignored the context
451 }
452
reed@google.com4f7c6152014-02-06 14:11:56 +0000453 const void* addr = image->peekPixels(&info, &rowBytes);
bsalomon49f085d2014-09-05 13:34:00 -0700454 bool success = SkToBool(addr);
reed@google.com4f7c6152014-02-06 14:11:56 +0000455 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
456 if (success) {
reede5ea5002014-09-03 11:54:58 -0700457 REPORTER_ASSERT(reporter, 10 == info.width());
458 REPORTER_ASSERT(reporter, 10 == info.height());
459 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType());
460 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() ||
461 kOpaque_SkAlphaType == info.alphaType());
reed@google.com4f7c6152014-02-06 14:11:56 +0000462 REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes);
463 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
464 }
reed96472de2014-12-10 09:53:42 -0800465
466 test_image_readpixels(reporter, image, pmcolor);
reed@google.com4f7c6152014-02-06 14:11:56 +0000467 }
reedde499882015-06-18 13:41:40 -0700468 REPORTER_ASSERT(reporter, NULL == releaseCtx.fData); // we released the data
reed@google.com4f7c6152014-02-06 14:11:56 +0000469}
470
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000471static void test_canvaspeek(skiatest::Reporter* reporter,
472 GrContextFactory* factory) {
473 static const struct {
474 SurfaceType fType;
475 bool fPeekShouldSucceed;
476 } gRec[] = {
477 { kRaster_SurfaceType, true },
478 { kRasterDirect_SurfaceType, true },
479#if SK_SUPPORT_GPU
480 { kGpu_SurfaceType, false },
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000481 { kGpuScratch_SurfaceType, false },
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000482#endif
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000483 };
484
485 const SkColor color = SK_ColorRED;
486 const SkPMColor pmcolor = SkPreMultiplyColor(color);
487
bsalomone904c092014-07-17 10:50:59 -0700488 int cnt;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000489#if SK_SUPPORT_GPU
bsalomone904c092014-07-17 10:50:59 -0700490 cnt = GrContextFactory::kGLContextTypeCnt;
491#else
492 cnt = 1;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000493#endif
494
bsalomone904c092014-07-17 10:50:59 -0700495 for (int i= 0; i < cnt; ++i) {
496 GrContext* context = NULL;
497#if SK_SUPPORT_GPU
498 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
499 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
500 continue;
501 }
502 context = factory->get(glCtxType);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000503
bsalomone904c092014-07-17 10:50:59 -0700504 if (NULL == context) {
505 continue;
506 }
507#endif
508 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
509 SkImageInfo info, requestInfo;
510 size_t rowBytes;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000511
bsalomon74f681d2015-06-23 14:38:48 -0700512 SkAutoTUnref<SkSurface> surface(create_surface(gRec[i].fType, context,
513 kPremul_SkAlphaType, &requestInfo));
bsalomone904c092014-07-17 10:50:59 -0700514 surface->getCanvas()->clear(color);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000515
bsalomone904c092014-07-17 10:50:59 -0700516 const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes);
bsalomon49f085d2014-09-05 13:34:00 -0700517 bool success = SkToBool(addr);
bsalomone904c092014-07-17 10:50:59 -0700518 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000519
bsalomone904c092014-07-17 10:50:59 -0700520 SkImageInfo info2;
521 size_t rb2;
522 const void* addr2 = surface->peekPixels(&info2, &rb2);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000523
bsalomone904c092014-07-17 10:50:59 -0700524 if (success) {
525 REPORTER_ASSERT(reporter, requestInfo == info);
526 REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes);
527 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
528
529 REPORTER_ASSERT(reporter, addr2 == addr);
530 REPORTER_ASSERT(reporter, info2 == info);
531 REPORTER_ASSERT(reporter, rb2 == rowBytes);
532 } else {
533 REPORTER_ASSERT(reporter, NULL == addr2);
534 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000535 }
536 }
537}
538
reed41e010c2015-06-09 12:16:53 -0700539// For compatibility with clients that still call accessBitmap(), we need to ensure that we bump
540// the bitmap's genID when we draw to it, else they won't know it has new values. When they are
541// exclusively using surface/image, and we can hide accessBitmap from device, we can remove this
542// test.
543static void test_accessPixels(skiatest::Reporter* reporter, GrContextFactory* factory) {
544 static const struct {
545 SurfaceType fType;
546 bool fPeekShouldSucceed;
547 } gRec[] = {
548 { kRaster_SurfaceType, true },
549 { kRasterDirect_SurfaceType, true },
550#if SK_SUPPORT_GPU
551 { kGpu_SurfaceType, false },
552 { kGpuScratch_SurfaceType, false },
553#endif
554 };
555
556 int cnt;
557#if SK_SUPPORT_GPU
558 cnt = GrContextFactory::kGLContextTypeCnt;
559#else
560 cnt = 1;
561#endif
562
563 for (int i= 0; i < cnt; ++i) {
564 GrContext* context = NULL;
565#if SK_SUPPORT_GPU
566 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
567 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
568 continue;
569 }
570 context = factory->get(glCtxType);
571
572 if (NULL == context) {
573 continue;
574 }
575#endif
576 for (size_t j = 0; j < SK_ARRAY_COUNT(gRec); ++j) {
577 SkImageInfo info, requestInfo;
578
bsalomon74f681d2015-06-23 14:38:48 -0700579 SkAutoTUnref<SkSurface> surface(create_surface(gRec[j].fType, context,
580 kPremul_SkAlphaType, &requestInfo));
reed41e010c2015-06-09 12:16:53 -0700581 SkCanvas* canvas = surface->getCanvas();
582 canvas->clear(0);
583
584 SkBaseDevice* device = canvas->getDevice_just_for_deprecated_compatibility_testing();
585 SkBitmap bm = device->accessBitmap(false);
586 uint32_t genID0 = bm.getGenerationID();
587 // Now we draw something, which needs to "dirty" the genID (sorta like copy-on-write)
588 canvas->drawColor(SK_ColorBLUE);
589 // Now check that we get a different genID
590 uint32_t genID1 = bm.getGenerationID();
591 REPORTER_ASSERT(reporter, genID0 != genID1);
592 }
593 }
594}
595
bsalomon74f681d2015-06-23 14:38:48 -0700596static void test_snap_alphatype(skiatest::Reporter* reporter, GrContextFactory* factory) {
597 GrContext* context = NULL;
598#if SK_SUPPORT_GPU
599 context = factory->get(GrContextFactory::kNative_GLContextType);
600 if (NULL == context) {
601 return;
602 }
603#endif
604 for (int opaque = 0; opaque < 2; ++opaque) {
605 SkAlphaType atype = SkToBool(opaque) ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
606 for (int st = 0; st < kSurfaceTypeCnt; ++st) {
607 SurfaceType stype = (SurfaceType)st;
608 SkAutoTUnref<SkSurface> surface(create_surface(stype, context, atype));
609 REPORTER_ASSERT(reporter, surface);
610 if (surface) {
611 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
612 REPORTER_ASSERT(reporter, image);
613 if (image) {
614 REPORTER_ASSERT(reporter, image->isOpaque() == SkToBool(opaque));
615 }
616 }
617 }
618 }
619}
620
junov@chromium.org995beb62013-03-28 13:49:22 +0000621static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType,
622 GrContext* context) {
623 // Verify that the right canvas commands trigger a copy on write
bsalomon74f681d2015-06-23 14:38:48 -0700624 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.org995beb62013-03-28 13:49:22 +0000625 SkAutoTUnref<SkSurface> aur_surface(surface);
626 SkCanvas* canvas = surface->getCanvas();
627
628 const SkRect testRect =
629 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
630 SkIntToScalar(4), SkIntToScalar(5));
junov@chromium.org995beb62013-03-28 13:49:22 +0000631 SkPath testPath;
632 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
633 SkIntToScalar(2), SkIntToScalar(1)));
634
635 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1);
636
637 SkRegion testRegion;
638 testRegion.setRect(testIRect);
639
640
641 const SkColor testColor = 0x01020304;
642 const SkPaint testPaint;
643 const SkPoint testPoints[3] = {
644 {SkIntToScalar(0), SkIntToScalar(0)},
645 {SkIntToScalar(2), SkIntToScalar(1)},
646 {SkIntToScalar(0), SkIntToScalar(2)}
647 };
648 const size_t testPointCount = 3;
649
650 SkBitmap testBitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000651 testBitmap.allocN32Pixels(10, 10);
robertphillips@google.comd1ce77d2013-10-09 12:51:09 +0000652 testBitmap.eraseColor(0);
junov@chromium.org995beb62013-03-28 13:49:22 +0000653
654 SkRRect testRRect;
655 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1);
656
657 SkString testText("Hello World");
658 const SkPoint testPoints2[] = {
659 { SkIntToScalar(0), SkIntToScalar(1) },
660 { SkIntToScalar(1), SkIntToScalar(1) },
661 { SkIntToScalar(2), SkIntToScalar(1) },
662 { SkIntToScalar(3), SkIntToScalar(1) },
663 { SkIntToScalar(4), SkIntToScalar(1) },
664 { SkIntToScalar(5), SkIntToScalar(1) },
665 { SkIntToScalar(6), SkIntToScalar(1) },
666 { SkIntToScalar(7), SkIntToScalar(1) },
667 { SkIntToScalar(8), SkIntToScalar(1) },
668 { SkIntToScalar(9), SkIntToScalar(1) },
669 { SkIntToScalar(10), SkIntToScalar(1) },
670 };
671
672#define EXPECT_COPY_ON_WRITE(command) \
673 { \
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000674 SkImage* imageBefore = surface->newImageSnapshot(); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000675 SkAutoTUnref<SkImage> aur_before(imageBefore); \
676 canvas-> command ; \
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000677 SkImage* imageAfter = surface->newImageSnapshot(); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000678 SkAutoTUnref<SkImage> aur_after(imageAfter); \
679 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \
680 }
681
682 EXPECT_COPY_ON_WRITE(clear(testColor))
683 EXPECT_COPY_ON_WRITE(drawPaint(testPaint))
684 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \
685 testPaint))
686 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint))
687 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint))
688 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint))
689 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint))
690 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0))
691 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect))
junov@chromium.org995beb62013-03-28 13:49:22 +0000692 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL))
693 EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL))
694 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint))
695 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \
696 testPaint))
697 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \
698 testPaint))
699}
700
junov@chromium.orgaf058352013-04-03 15:03:26 +0000701static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter,
702 SurfaceType surfaceType,
703 GrContext* context) {
704 // This test succeeds by not triggering an assertion.
705 // The test verifies that the surface remains writable (usable) after
706 // acquiring and releasing a snapshot without triggering a copy on write.
bsalomon74f681d2015-06-23 14:38:48 -0700707 SkAutoTUnref<SkSurface> surface(create_surface(surfaceType, context));
junov@chromium.orgaf058352013-04-03 15:03:26 +0000708 SkCanvas* canvas = surface->getCanvas();
709 canvas->clear(1);
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000710 surface->newImageSnapshot()->unref(); // Create and destroy SkImage
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000711 canvas->clear(2); // Must not assert internally
junov@chromium.org995beb62013-03-28 13:49:22 +0000712}
junov@chromium.orgda904742013-05-01 22:38:16 +0000713
junov@chromium.orgb516a412013-05-01 22:49:59 +0000714#if SK_SUPPORT_GPU
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000715static void Test_crbug263329(skiatest::Reporter* reporter,
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000716 SurfaceType surfaceType,
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000717 GrContext* context) {
718 // This is a regression test for crbug.com/263329
719 // Bug was caused by onCopyOnWrite releasing the old surface texture
720 // back to the scratch texture pool even though the texture is used
721 // by and active SkImage_Gpu.
bsalomon74f681d2015-06-23 14:38:48 -0700722 SkAutoTUnref<SkSurface> surface1(create_surface(surfaceType, context));
723 SkAutoTUnref<SkSurface> surface2(create_surface(surfaceType, context));
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000724 SkCanvas* canvas1 = surface1->getCanvas();
725 SkCanvas* canvas2 = surface2->getCanvas();
726 canvas1->clear(1);
727 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot());
728 // Trigger copy on write, new backing is a scratch texture
729 canvas1->clear(2);
730 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot());
731 // Trigger copy on write, old backing should not be returned to scratch
732 // pool because it is held by image2
733 canvas1->clear(3);
734
735 canvas2->clear(4);
736 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot());
737 // Trigger copy on write on surface2. The new backing store should not
738 // be recycling a texture that is held by an existing image.
739 canvas2->clear(5);
740 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot());
bsalomon55812362015-06-10 08:49:28 -0700741 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image3)->getTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000742 // The following assertion checks crbug.com/263329
bsalomon55812362015-06-10 08:49:28 -0700743 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image2)->getTexture());
744 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image1)->getTexture());
745 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image2)->getTexture());
746 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image1)->getTexture());
747 REPORTER_ASSERT(reporter, as_IB(image2)->getTexture() != as_IB(image1)->getTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000748}
749
junov@chromium.orgda904742013-05-01 22:38:16 +0000750static void TestGetTexture(skiatest::Reporter* reporter,
751 SurfaceType surfaceType,
752 GrContext* context) {
bsalomon74f681d2015-06-23 14:38:48 -0700753 SkAutoTUnref<SkSurface> surface(create_surface(surfaceType, context));
junov@chromium.orgda904742013-05-01 22:38:16 +0000754 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
bsalomon55812362015-06-10 08:49:28 -0700755 GrTexture* texture = as_IB(image)->getTexture();
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000756 if (surfaceType == kGpu_SurfaceType || surfaceType == kGpuScratch_SurfaceType) {
bsalomon49f085d2014-09-05 13:34:00 -0700757 REPORTER_ASSERT(reporter, texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000758 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle());
759 } else {
760 REPORTER_ASSERT(reporter, NULL == texture);
761 }
762 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
bsalomon55812362015-06-10 08:49:28 -0700763 REPORTER_ASSERT(reporter, as_IB(image)->getTexture() == texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000764}
bsalomoneaaaf0b2015-01-23 08:08:04 -0800765
bsalomon3582d3e2015-02-13 14:20:05 -0800766#include "GrGpuResourcePriv.h"
bsalomoneaaaf0b2015-01-23 08:08:04 -0800767#include "SkGpuDevice.h"
768#include "SkImage_Gpu.h"
769#include "SkSurface_Gpu.h"
770
771SkSurface::Budgeted is_budgeted(SkSurface* surf) {
bsalomon3582d3e2015-02-13 14:20:05 -0800772 return ((SkSurface_Gpu*)surf)->getDevice()->accessRenderTarget()->resourcePriv().isBudgeted() ?
bsalomoneaaaf0b2015-01-23 08:08:04 -0800773 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
774}
775
776SkSurface::Budgeted is_budgeted(SkImage* image) {
bsalomon3582d3e2015-02-13 14:20:05 -0800777 return ((SkImage_Gpu*)image)->getTexture()->resourcePriv().isBudgeted() ?
bsalomoneaaaf0b2015-01-23 08:08:04 -0800778 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
779}
780
781static void test_surface_budget(skiatest::Reporter* reporter, GrContext* context) {
782 SkImageInfo info = SkImageInfo::MakeN32Premul(8,8);
783 for (int i = 0; i < 2; ++i) {
784 SkSurface::Budgeted sbudgeted = i ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
785 for (int j = 0; j < 2; ++j) {
786 SkSurface::Budgeted ibudgeted = j ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
787 SkAutoTUnref<SkSurface>
788 surface(SkSurface::NewRenderTarget(context, sbudgeted, info, 0));
789 SkASSERT(surface);
790 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
791
mtklein31ff2982015-01-24 11:27:27 -0800792 SkAutoTUnref<SkImage> image(surface->newImageSnapshot(ibudgeted));
bsalomoneaaaf0b2015-01-23 08:08:04 -0800793
794 // Initially the image shares a texture with the surface, and the surface decides
795 // whether it is budgeted or not.
796 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
797 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(image));
798
799 // Now trigger copy-on-write
800 surface->getCanvas()->clear(SK_ColorBLUE);
801
802 // They don't share a texture anymore. They should each have made their own budget
803 // decision.
804 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
805 REPORTER_ASSERT(reporter, ibudgeted == is_budgeted(image));
806 }
807 }
808}
809
junov@chromium.orgb516a412013-05-01 22:49:59 +0000810#endif
junov@chromium.orgda904742013-05-01 22:38:16 +0000811
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000812static void TestSurfaceNoCanvas(skiatest::Reporter* reporter,
813 SurfaceType surfaceType,
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000814 GrContext* context,
815 SkSurface::ContentChangeMode mode) {
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000816 // Verifies the robustness of SkSurface for handling use cases where calls
817 // are made before a canvas is created.
818 {
819 // Test passes by not asserting
bsalomon74f681d2015-06-23 14:38:48 -0700820 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000821 SkAutoTUnref<SkSurface> aur_surface(surface);
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000822 surface->notifyContentWillChange(mode);
robertphillips@google.com03087072013-10-02 16:42:21 +0000823 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000824 }
825 {
bsalomon74f681d2015-06-23 14:38:48 -0700826 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000827 SkAutoTUnref<SkSurface> aur_surface(surface);
828 SkImage* image1 = surface->newImageSnapshot();
829 SkAutoTUnref<SkImage> aur_image1(image1);
robertphillips@google.com03087072013-10-02 16:42:21 +0000830 SkDEBUGCODE(image1->validate();)
831 SkDEBUGCODE(surface->validate();)
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000832 surface->notifyContentWillChange(mode);
robertphillips@google.com03087072013-10-02 16:42:21 +0000833 SkDEBUGCODE(image1->validate();)
834 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000835 SkImage* image2 = surface->newImageSnapshot();
836 SkAutoTUnref<SkImage> aur_image2(image2);
robertphillips@google.com03087072013-10-02 16:42:21 +0000837 SkDEBUGCODE(image2->validate();)
838 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000839 REPORTER_ASSERT(reporter, image1 != image2);
840 }
skia.committer@gmail.com45fb8b62013-04-17 07:00:56 +0000841
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000842}
junov@chromium.org995beb62013-03-28 13:49:22 +0000843
tfarina@chromium.org4ee16bf2014-01-10 22:08:27 +0000844DEF_GPUTEST(Surface, reporter, factory) {
reed@google.com999da9c2014-02-06 13:43:07 +0000845 test_image(reporter);
846
junov@chromium.orgaf058352013-04-03 15:03:26 +0000847 TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL);
junov@chromium.orgaf058352013-04-03 15:03:26 +0000848 TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL);
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000849 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode);
850 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000851
reedb2497c22014-12-31 12:31:43 -0800852 test_empty_image(reporter);
853 test_empty_surface(reporter, NULL);
854
reed67f2eb42014-12-10 06:54:06 -0800855 test_imagepeek(reporter, factory);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000856 test_canvaspeek(reporter, factory);
857
reed41e010c2015-06-09 12:16:53 -0700858 test_accessPixels(reporter, factory);
859
bsalomon74f681d2015-06-23 14:38:48 -0700860 test_snap_alphatype(reporter, factory);
861
junov@chromium.orgb516a412013-05-01 22:49:59 +0000862#if SK_SUPPORT_GPU
junov@chromium.orgda904742013-05-01 22:38:16 +0000863 TestGetTexture(reporter, kRaster_SurfaceType, NULL);
bsalomon49f085d2014-09-05 13:34:00 -0700864 if (factory) {
bsalomone904c092014-07-17 10:50:59 -0700865 for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
866 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
867 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
868 continue;
869 }
870 GrContext* context = factory->get(glCtxType);
bsalomon49f085d2014-09-05 13:34:00 -0700871 if (context) {
bsalomone904c092014-07-17 10:50:59 -0700872 Test_crbug263329(reporter, kGpu_SurfaceType, context);
873 Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
874 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
875 TestSurfaceCopyOnWrite(reporter, kGpuScratch_SurfaceType, context);
876 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context);
877 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpuScratch_SurfaceType, context);
878 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
879 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
880 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
881 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
882 TestGetTexture(reporter, kGpu_SurfaceType, context);
883 TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
reedb2497c22014-12-31 12:31:43 -0800884 test_empty_surface(reporter, context);
bsalomoneaaaf0b2015-01-23 08:08:04 -0800885 test_surface_budget(reporter, context);
bsalomond3e259a2015-06-30 12:04:40 -0700886 test_wrapped_surface(reporter, context);
bsalomone904c092014-07-17 10:50:59 -0700887 }
robertphillips@google.com3bddb382013-11-12 13:51:03 +0000888 }
junov@chromium.orgaf058352013-04-03 15:03:26 +0000889 }
junov@chromium.org995beb62013-03-28 13:49:22 +0000890#endif
891}
reed8b26b992015-05-07 15:36:17 -0700892
893#if SK_SUPPORT_GPU
reedde499882015-06-18 13:41:40 -0700894
895struct ReleaseTextureContext {
896 ReleaseTextureContext(skiatest::Reporter* reporter) {
897 fReporter = reporter;
898 fIsReleased = false;
899 }
900
901 skiatest::Reporter* fReporter;
902 bool fIsReleased;
903
904 void doRelease() {
905 REPORTER_ASSERT(fReporter, false == fIsReleased);
906 fIsReleased = true;
907 }
908
909 static void ReleaseProc(void* context) {
910 ((ReleaseTextureContext*)context)->doRelease();
911 }
912};
913
914static SkImage* make_desc_image(GrContext* ctx, int w, int h, GrBackendObject texID,
915 ReleaseTextureContext* releaseContext) {
reed8b26b992015-05-07 15:36:17 -0700916 GrBackendTextureDesc desc;
917 desc.fConfig = kSkia8888_GrPixelConfig;
918 // need to be a rendertarget for now...
919 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
920 desc.fWidth = w;
921 desc.fHeight = h;
922 desc.fSampleCnt = 0;
923 desc.fTextureHandle = texID;
reedde499882015-06-18 13:41:40 -0700924 return releaseContext
925 ? SkImage::NewFromTexture(ctx, desc, kPremul_SkAlphaType,
926 ReleaseTextureContext::ReleaseProc, releaseContext)
927 : SkImage::NewFromTextureCopy(ctx, desc, kPremul_SkAlphaType);
reed8b26b992015-05-07 15:36:17 -0700928}
929
930static void test_image_color(skiatest::Reporter* reporter, SkImage* image, SkPMColor expected) {
931 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
932 SkPMColor pixel;
933 REPORTER_ASSERT(reporter, image->readPixels(info, &pixel, sizeof(pixel), 0, 0));
934 REPORTER_ASSERT(reporter, pixel == expected);
935}
936
937DEF_GPUTEST(SkImage_NewFromTexture, reporter, factory) {
938 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
939 if (!ctx) {
940 REPORTER_ASSERT(reporter, false);
941 return;
942 }
943 GrTextureProvider* provider = ctx->textureProvider();
944
945 const int w = 10;
946 const int h = 10;
947 SkPMColor storage[w * h];
948 const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED);
949 sk_memset32(storage, expected0, w * h);
950
951 GrSurfaceDesc desc;
952 desc.fFlags = kRenderTarget_GrSurfaceFlag; // needs to be a rendertarget for readpixels();
953 desc.fOrigin = kDefault_GrSurfaceOrigin;
954 desc.fWidth = w;
955 desc.fHeight = h;
956 desc.fConfig = kSkia8888_GrPixelConfig;
957 desc.fSampleCnt = 0;
958
959 SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, false, storage, w * 4));
960 if (!tex) {
961 REPORTER_ASSERT(reporter, false);
962 return;
963 }
reedde499882015-06-18 13:41:40 -0700964
reed8b26b992015-05-07 15:36:17 -0700965 GrBackendObject srcTex = tex->getTextureHandle();
reedde499882015-06-18 13:41:40 -0700966 ReleaseTextureContext releaseCtx(reporter);
967
968 SkAutoTUnref<SkImage> refImg(make_desc_image(ctx, w, h, srcTex, &releaseCtx));
969 SkAutoTUnref<SkImage> cpyImg(make_desc_image(ctx, w, h, srcTex, NULL));
reed8b26b992015-05-07 15:36:17 -0700970
971 test_image_color(reporter, refImg, expected0);
972 test_image_color(reporter, cpyImg, expected0);
973
974 // Now lets jam new colors into our "external" texture, and see if the images notice
975 const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE);
976 sk_memset32(storage, expected1, w * h);
977 tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp);
978
979 // We expect the ref'd image to see the new color, but cpy'd one should still see the old color
980 test_image_color(reporter, refImg, expected1);
981 test_image_color(reporter, cpyImg, expected0);
reedde499882015-06-18 13:41:40 -0700982
983 // Now exercise the release proc
984 REPORTER_ASSERT(reporter, !releaseCtx.fIsReleased);
985 refImg.reset(NULL); // force a release of the image
986 REPORTER_ASSERT(reporter, releaseCtx.fIsReleased);
reed8b26b992015-05-07 15:36:17 -0700987}
988#endif