blob: cfaa6692628d3478c1effd453894ca9baf263e44 [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
105static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext* ctx) {
106 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.
118 const GrGLInterface* gl = tt.glInterface();
119 if (!gl) {
120 return;
121 }
122
123 // 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
147 GrBackendTextureDesc wrappedDesc;
bsalomon7a617932015-06-16 08:07:16 -0700148 wrappedDesc.fConfig = kRGBA_8888_GrPixelConfig;
149 wrappedDesc.fWidth = kW;
150 wrappedDesc.fHeight = kH;
151 wrappedDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
152 wrappedDesc.fSampleCnt = 0;
bsalomone4579ad2015-04-08 08:38:40 -0700153 wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
bsalomon7a617932015-06-16 08:07:16 -0700154 wrappedDesc.fTextureHandle = texID;
bsalomone4579ad2015-04-08 08:38:40 -0700155
156 SkAutoTUnref<SkSurface> surface(SkSurface::NewWrappedRenderTarget(ctx, wrappedDesc, NULL));
157 REPORTER_ASSERT(reporter, surface);
bsalomon7a617932015-06-16 08:07:16 -0700158 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;
182 }
183 }
184 }
185 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 }
193 }
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
bsalomon74f681d2015-06-23 14:38:48 -0700226static SkImage* create_image(ImageType imageType, GrContext* context, SkColor color,
227 ReleaseDataContext* releaseContext) {
reed@google.com4f7c6152014-02-06 14:11:56 +0000228 const SkPMColor pmcolor = SkPreMultiplyColor(color);
229 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
230 const size_t rowBytes = info.minRowBytes();
reede5ea5002014-09-03 11:54:58 -0700231 const size_t size = rowBytes * info.height();
reed@google.com4f7c6152014-02-06 14:11:56 +0000232
reed9594da12014-09-12 12:12:27 -0700233 SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
234 void* addr = data->writable_data();
reed@google.com4f7c6152014-02-06 14:11:56 +0000235 sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2));
reed@google.com4f7c6152014-02-06 14:11:56 +0000236
237 switch (imageType) {
238 case kRasterCopy_ImageType:
239 return SkImage::NewRasterCopy(info, addr, rowBytes);
240 case kRasterData_ImageType:
241 return SkImage::NewRasterData(info, data, rowBytes);
reedde499882015-06-18 13:41:40 -0700242 case kRasterProc_ImageType:
243 SkASSERT(releaseContext);
244 releaseContext->fData = SkRef(data.get());
245 return SkImage::NewFromRaster(info, addr, rowBytes,
246 ReleaseDataContext::Release, releaseContext);
reed67f2eb42014-12-10 06:54:06 -0800247 case kGpu_ImageType: {
bsalomonafe30052015-01-16 07:32:33 -0800248 SkAutoTUnref<SkSurface> surf(
249 SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0));
reed67f2eb42014-12-10 06:54:06 -0800250 surf->getCanvas()->clear(color);
251 return surf->newImageSnapshot();
252 }
reed@google.com4f7c6152014-02-06 14:11:56 +0000253 case kCodec_ImageType: {
254 SkBitmap bitmap;
commit-bot@chromium.org00f8d6c2014-05-29 15:57:20 +0000255 bitmap.installPixels(info, addr, rowBytes);
reed@google.com4f7c6152014-02-06 14:11:56 +0000256 SkAutoTUnref<SkData> src(
reed67f2eb42014-12-10 06:54:06 -0800257 SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100));
reed871872f2015-06-22 12:48:26 -0700258 return SkImage::NewFromEncoded(src);
reed@google.com4f7c6152014-02-06 14:11:56 +0000259 }
260 }
261 SkASSERT(false);
262 return NULL;
263}
264
reed96472de2014-12-10 09:53:42 -0800265static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) {
266 sk_memset32(pixels, color, count);
267}
268static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) {
269 for (int i = 0; i < count; ++i) {
270 if (pixels[i] != expected) {
271 return false;
272 }
273 }
274 return true;
275}
276
277static void test_image_readpixels(skiatest::Reporter* reporter, SkImage* image,
278 SkPMColor expected) {
279 const SkPMColor notExpected = ~expected;
280
281 const int w = 2, h = 2;
282 const size_t rowBytes = w * sizeof(SkPMColor);
283 SkPMColor pixels[w*h];
284
285 SkImageInfo info;
286
287 info = SkImageInfo::MakeUnknown(w, h);
288 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0));
289
290 // out-of-bounds should fail
291 info = SkImageInfo::MakeN32Premul(w, h);
292 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0));
293 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h));
294 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0));
295 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height()));
296
297 // top-left should succeed
298 set_pixels(pixels, w*h, notExpected);
299 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0));
300 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
301
302 // bottom-right should succeed
303 set_pixels(pixels, w*h, notExpected);
304 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
305 image->width() - w, image->height() - h));
306 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
307
308 // partial top-left should succeed
309 set_pixels(pixels, w*h, notExpected);
310 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1));
311 REPORTER_ASSERT(reporter, pixels[3] == expected);
312 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected));
313
314 // partial bottom-right should succeed
315 set_pixels(pixels, w*h, notExpected);
316 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
317 image->width() - 1, image->height() - 1));
318 REPORTER_ASSERT(reporter, pixels[0] == expected);
319 REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected));
320}
321
reed67f2eb42014-12-10 06:54:06 -0800322static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* factory) {
reed@google.com4f7c6152014-02-06 14:11:56 +0000323 static const struct {
324 ImageType fType;
325 bool fPeekShouldSucceed;
reed67f2eb42014-12-10 06:54:06 -0800326 const char* fName;
reed@google.com4f7c6152014-02-06 14:11:56 +0000327 } gRec[] = {
reed67f2eb42014-12-10 06:54:06 -0800328 { kRasterCopy_ImageType, true, "RasterCopy" },
329 { kRasterData_ImageType, true, "RasterData" },
reedde499882015-06-18 13:41:40 -0700330 { kRasterProc_ImageType, true, "RasterProc" },
reed67f2eb42014-12-10 06:54:06 -0800331 { kGpu_ImageType, false, "Gpu" },
332 { kCodec_ImageType, false, "Codec" },
reed@google.com4f7c6152014-02-06 14:11:56 +0000333 };
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000334
reed@google.com4f7c6152014-02-06 14:11:56 +0000335 const SkColor color = SK_ColorRED;
336 const SkPMColor pmcolor = SkPreMultiplyColor(color);
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000337
reed67f2eb42014-12-10 06:54:06 -0800338 GrContext* ctx = NULL;
339#if SK_SUPPORT_GPU
340 ctx = factory->get(GrContextFactory::kNative_GLContextType);
senorblancoc8e93402015-04-21 07:20:36 -0700341 if (NULL == ctx) {
senorblanco84bfd392015-04-21 06:59:17 -0700342 return;
343 }
reed67f2eb42014-12-10 06:54:06 -0800344#endif
345
reedde499882015-06-18 13:41:40 -0700346 ReleaseDataContext releaseCtx;
347 releaseCtx.fReporter = reporter;
348
reed@google.com4f7c6152014-02-06 14:11:56 +0000349 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
350 SkImageInfo info;
351 size_t rowBytes;
skia.committer@gmail.com02d6f542014-02-14 03:02:05 +0000352
reedde499882015-06-18 13:41:40 -0700353 releaseCtx.fData = NULL;
bsalomon74f681d2015-06-23 14:38:48 -0700354 SkAutoTUnref<SkImage> image(create_image(gRec[i].fType, ctx, color, &releaseCtx));
reed@google.com4f7c6152014-02-06 14:11:56 +0000355 if (!image.get()) {
reed67f2eb42014-12-10 06:54:06 -0800356 SkDebugf("failed to createImage[%d] %s\n", i, gRec[i].fName);
reed@google.com4f7c6152014-02-06 14:11:56 +0000357 continue; // gpu may not be enabled
358 }
reedde499882015-06-18 13:41:40 -0700359 if (kRasterProc_ImageType == gRec[i].fType) {
360 REPORTER_ASSERT(reporter, NULL != releaseCtx.fData); // we are tracking the data
361 } else {
362 REPORTER_ASSERT(reporter, NULL == releaseCtx.fData); // we ignored the context
363 }
364
reed@google.com4f7c6152014-02-06 14:11:56 +0000365 const void* addr = image->peekPixels(&info, &rowBytes);
bsalomon49f085d2014-09-05 13:34:00 -0700366 bool success = SkToBool(addr);
reed@google.com4f7c6152014-02-06 14:11:56 +0000367 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
368 if (success) {
reede5ea5002014-09-03 11:54:58 -0700369 REPORTER_ASSERT(reporter, 10 == info.width());
370 REPORTER_ASSERT(reporter, 10 == info.height());
371 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType());
372 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() ||
373 kOpaque_SkAlphaType == info.alphaType());
reed@google.com4f7c6152014-02-06 14:11:56 +0000374 REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes);
375 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
376 }
reed96472de2014-12-10 09:53:42 -0800377
378 test_image_readpixels(reporter, image, pmcolor);
reed@google.com4f7c6152014-02-06 14:11:56 +0000379 }
reedde499882015-06-18 13:41:40 -0700380 REPORTER_ASSERT(reporter, NULL == releaseCtx.fData); // we released the data
reed@google.com4f7c6152014-02-06 14:11:56 +0000381}
382
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000383static void test_canvaspeek(skiatest::Reporter* reporter,
384 GrContextFactory* factory) {
385 static const struct {
386 SurfaceType fType;
387 bool fPeekShouldSucceed;
388 } gRec[] = {
389 { kRaster_SurfaceType, true },
390 { kRasterDirect_SurfaceType, true },
391#if SK_SUPPORT_GPU
392 { kGpu_SurfaceType, false },
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000393 { kGpuScratch_SurfaceType, false },
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000394#endif
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000395 };
396
397 const SkColor color = SK_ColorRED;
398 const SkPMColor pmcolor = SkPreMultiplyColor(color);
399
bsalomone904c092014-07-17 10:50:59 -0700400 int cnt;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000401#if SK_SUPPORT_GPU
bsalomone904c092014-07-17 10:50:59 -0700402 cnt = GrContextFactory::kGLContextTypeCnt;
403#else
404 cnt = 1;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000405#endif
406
bsalomone904c092014-07-17 10:50:59 -0700407 for (int i= 0; i < cnt; ++i) {
408 GrContext* context = NULL;
409#if SK_SUPPORT_GPU
410 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
411 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
412 continue;
413 }
414 context = factory->get(glCtxType);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000415
bsalomone904c092014-07-17 10:50:59 -0700416 if (NULL == context) {
417 continue;
418 }
419#endif
420 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
421 SkImageInfo info, requestInfo;
422 size_t rowBytes;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000423
bsalomon74f681d2015-06-23 14:38:48 -0700424 SkAutoTUnref<SkSurface> surface(create_surface(gRec[i].fType, context,
425 kPremul_SkAlphaType, &requestInfo));
bsalomone904c092014-07-17 10:50:59 -0700426 surface->getCanvas()->clear(color);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000427
bsalomone904c092014-07-17 10:50:59 -0700428 const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes);
bsalomon49f085d2014-09-05 13:34:00 -0700429 bool success = SkToBool(addr);
bsalomone904c092014-07-17 10:50:59 -0700430 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000431
bsalomone904c092014-07-17 10:50:59 -0700432 SkImageInfo info2;
433 size_t rb2;
434 const void* addr2 = surface->peekPixels(&info2, &rb2);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000435
bsalomone904c092014-07-17 10:50:59 -0700436 if (success) {
437 REPORTER_ASSERT(reporter, requestInfo == info);
438 REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes);
439 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
440
441 REPORTER_ASSERT(reporter, addr2 == addr);
442 REPORTER_ASSERT(reporter, info2 == info);
443 REPORTER_ASSERT(reporter, rb2 == rowBytes);
444 } else {
445 REPORTER_ASSERT(reporter, NULL == addr2);
446 }
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000447 }
448 }
449}
450
reed41e010c2015-06-09 12:16:53 -0700451// For compatibility with clients that still call accessBitmap(), we need to ensure that we bump
452// the bitmap's genID when we draw to it, else they won't know it has new values. When they are
453// exclusively using surface/image, and we can hide accessBitmap from device, we can remove this
454// test.
455static void test_accessPixels(skiatest::Reporter* reporter, GrContextFactory* factory) {
456 static const struct {
457 SurfaceType fType;
458 bool fPeekShouldSucceed;
459 } gRec[] = {
460 { kRaster_SurfaceType, true },
461 { kRasterDirect_SurfaceType, true },
462#if SK_SUPPORT_GPU
463 { kGpu_SurfaceType, false },
464 { kGpuScratch_SurfaceType, false },
465#endif
466 };
467
468 int cnt;
469#if SK_SUPPORT_GPU
470 cnt = GrContextFactory::kGLContextTypeCnt;
471#else
472 cnt = 1;
473#endif
474
475 for (int i= 0; i < cnt; ++i) {
476 GrContext* context = NULL;
477#if SK_SUPPORT_GPU
478 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
479 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
480 continue;
481 }
482 context = factory->get(glCtxType);
483
484 if (NULL == context) {
485 continue;
486 }
487#endif
488 for (size_t j = 0; j < SK_ARRAY_COUNT(gRec); ++j) {
489 SkImageInfo info, requestInfo;
490
bsalomon74f681d2015-06-23 14:38:48 -0700491 SkAutoTUnref<SkSurface> surface(create_surface(gRec[j].fType, context,
492 kPremul_SkAlphaType, &requestInfo));
reed41e010c2015-06-09 12:16:53 -0700493 SkCanvas* canvas = surface->getCanvas();
494 canvas->clear(0);
495
496 SkBaseDevice* device = canvas->getDevice_just_for_deprecated_compatibility_testing();
497 SkBitmap bm = device->accessBitmap(false);
498 uint32_t genID0 = bm.getGenerationID();
499 // Now we draw something, which needs to "dirty" the genID (sorta like copy-on-write)
500 canvas->drawColor(SK_ColorBLUE);
501 // Now check that we get a different genID
502 uint32_t genID1 = bm.getGenerationID();
503 REPORTER_ASSERT(reporter, genID0 != genID1);
504 }
505 }
506}
507
bsalomon74f681d2015-06-23 14:38:48 -0700508static void test_snap_alphatype(skiatest::Reporter* reporter, GrContextFactory* factory) {
509 GrContext* context = NULL;
510#if SK_SUPPORT_GPU
511 context = factory->get(GrContextFactory::kNative_GLContextType);
512 if (NULL == context) {
513 return;
514 }
515#endif
516 for (int opaque = 0; opaque < 2; ++opaque) {
517 SkAlphaType atype = SkToBool(opaque) ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
518 for (int st = 0; st < kSurfaceTypeCnt; ++st) {
519 SurfaceType stype = (SurfaceType)st;
520 SkAutoTUnref<SkSurface> surface(create_surface(stype, context, atype));
521 REPORTER_ASSERT(reporter, surface);
522 if (surface) {
523 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
524 REPORTER_ASSERT(reporter, image);
525 if (image) {
526 REPORTER_ASSERT(reporter, image->isOpaque() == SkToBool(opaque));
527 }
528 }
529 }
530 }
531}
532
junov@chromium.org995beb62013-03-28 13:49:22 +0000533static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType,
534 GrContext* context) {
535 // Verify that the right canvas commands trigger a copy on write
bsalomon74f681d2015-06-23 14:38:48 -0700536 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.org995beb62013-03-28 13:49:22 +0000537 SkAutoTUnref<SkSurface> aur_surface(surface);
538 SkCanvas* canvas = surface->getCanvas();
539
540 const SkRect testRect =
541 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
542 SkIntToScalar(4), SkIntToScalar(5));
junov@chromium.org995beb62013-03-28 13:49:22 +0000543 SkPath testPath;
544 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
545 SkIntToScalar(2), SkIntToScalar(1)));
546
547 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1);
548
549 SkRegion testRegion;
550 testRegion.setRect(testIRect);
551
552
553 const SkColor testColor = 0x01020304;
554 const SkPaint testPaint;
555 const SkPoint testPoints[3] = {
556 {SkIntToScalar(0), SkIntToScalar(0)},
557 {SkIntToScalar(2), SkIntToScalar(1)},
558 {SkIntToScalar(0), SkIntToScalar(2)}
559 };
560 const size_t testPointCount = 3;
561
562 SkBitmap testBitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000563 testBitmap.allocN32Pixels(10, 10);
robertphillips@google.comd1ce77d2013-10-09 12:51:09 +0000564 testBitmap.eraseColor(0);
junov@chromium.org995beb62013-03-28 13:49:22 +0000565
566 SkRRect testRRect;
567 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1);
568
569 SkString testText("Hello World");
570 const SkPoint testPoints2[] = {
571 { SkIntToScalar(0), SkIntToScalar(1) },
572 { SkIntToScalar(1), SkIntToScalar(1) },
573 { SkIntToScalar(2), SkIntToScalar(1) },
574 { SkIntToScalar(3), SkIntToScalar(1) },
575 { SkIntToScalar(4), SkIntToScalar(1) },
576 { SkIntToScalar(5), SkIntToScalar(1) },
577 { SkIntToScalar(6), SkIntToScalar(1) },
578 { SkIntToScalar(7), SkIntToScalar(1) },
579 { SkIntToScalar(8), SkIntToScalar(1) },
580 { SkIntToScalar(9), SkIntToScalar(1) },
581 { SkIntToScalar(10), SkIntToScalar(1) },
582 };
583
584#define EXPECT_COPY_ON_WRITE(command) \
585 { \
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000586 SkImage* imageBefore = surface->newImageSnapshot(); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000587 SkAutoTUnref<SkImage> aur_before(imageBefore); \
588 canvas-> command ; \
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000589 SkImage* imageAfter = surface->newImageSnapshot(); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000590 SkAutoTUnref<SkImage> aur_after(imageAfter); \
591 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \
592 }
593
594 EXPECT_COPY_ON_WRITE(clear(testColor))
595 EXPECT_COPY_ON_WRITE(drawPaint(testPaint))
596 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \
597 testPaint))
598 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint))
599 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint))
600 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint))
601 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint))
602 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0))
603 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect))
junov@chromium.org995beb62013-03-28 13:49:22 +0000604 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL))
605 EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL))
606 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint))
607 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \
608 testPaint))
609 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \
610 testPaint))
611}
612
junov@chromium.orgaf058352013-04-03 15:03:26 +0000613static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter,
614 SurfaceType surfaceType,
615 GrContext* context) {
616 // This test succeeds by not triggering an assertion.
617 // The test verifies that the surface remains writable (usable) after
618 // acquiring and releasing a snapshot without triggering a copy on write.
bsalomon74f681d2015-06-23 14:38:48 -0700619 SkAutoTUnref<SkSurface> surface(create_surface(surfaceType, context));
junov@chromium.orgaf058352013-04-03 15:03:26 +0000620 SkCanvas* canvas = surface->getCanvas();
621 canvas->clear(1);
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000622 surface->newImageSnapshot()->unref(); // Create and destroy SkImage
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000623 canvas->clear(2); // Must not assert internally
junov@chromium.org995beb62013-03-28 13:49:22 +0000624}
junov@chromium.orgda904742013-05-01 22:38:16 +0000625
junov@chromium.orgb516a412013-05-01 22:49:59 +0000626#if SK_SUPPORT_GPU
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000627static void Test_crbug263329(skiatest::Reporter* reporter,
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000628 SurfaceType surfaceType,
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000629 GrContext* context) {
630 // This is a regression test for crbug.com/263329
631 // Bug was caused by onCopyOnWrite releasing the old surface texture
632 // back to the scratch texture pool even though the texture is used
633 // by and active SkImage_Gpu.
bsalomon74f681d2015-06-23 14:38:48 -0700634 SkAutoTUnref<SkSurface> surface1(create_surface(surfaceType, context));
635 SkAutoTUnref<SkSurface> surface2(create_surface(surfaceType, context));
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000636 SkCanvas* canvas1 = surface1->getCanvas();
637 SkCanvas* canvas2 = surface2->getCanvas();
638 canvas1->clear(1);
639 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot());
640 // Trigger copy on write, new backing is a scratch texture
641 canvas1->clear(2);
642 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot());
643 // Trigger copy on write, old backing should not be returned to scratch
644 // pool because it is held by image2
645 canvas1->clear(3);
646
647 canvas2->clear(4);
648 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot());
649 // Trigger copy on write on surface2. The new backing store should not
650 // be recycling a texture that is held by an existing image.
651 canvas2->clear(5);
652 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot());
bsalomon55812362015-06-10 08:49:28 -0700653 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image3)->getTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000654 // The following assertion checks crbug.com/263329
bsalomon55812362015-06-10 08:49:28 -0700655 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image2)->getTexture());
656 REPORTER_ASSERT(reporter, as_IB(image4)->getTexture() != as_IB(image1)->getTexture());
657 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image2)->getTexture());
658 REPORTER_ASSERT(reporter, as_IB(image3)->getTexture() != as_IB(image1)->getTexture());
659 REPORTER_ASSERT(reporter, as_IB(image2)->getTexture() != as_IB(image1)->getTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000660}
661
junov@chromium.orgda904742013-05-01 22:38:16 +0000662static void TestGetTexture(skiatest::Reporter* reporter,
663 SurfaceType surfaceType,
664 GrContext* context) {
bsalomon74f681d2015-06-23 14:38:48 -0700665 SkAutoTUnref<SkSurface> surface(create_surface(surfaceType, context));
junov@chromium.orgda904742013-05-01 22:38:16 +0000666 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
bsalomon55812362015-06-10 08:49:28 -0700667 GrTexture* texture = as_IB(image)->getTexture();
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000668 if (surfaceType == kGpu_SurfaceType || surfaceType == kGpuScratch_SurfaceType) {
bsalomon49f085d2014-09-05 13:34:00 -0700669 REPORTER_ASSERT(reporter, texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000670 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle());
671 } else {
672 REPORTER_ASSERT(reporter, NULL == texture);
673 }
674 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
bsalomon55812362015-06-10 08:49:28 -0700675 REPORTER_ASSERT(reporter, as_IB(image)->getTexture() == texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000676}
bsalomoneaaaf0b2015-01-23 08:08:04 -0800677
bsalomon3582d3e2015-02-13 14:20:05 -0800678#include "GrGpuResourcePriv.h"
bsalomoneaaaf0b2015-01-23 08:08:04 -0800679#include "SkGpuDevice.h"
680#include "SkImage_Gpu.h"
681#include "SkSurface_Gpu.h"
682
683SkSurface::Budgeted is_budgeted(SkSurface* surf) {
bsalomon3582d3e2015-02-13 14:20:05 -0800684 return ((SkSurface_Gpu*)surf)->getDevice()->accessRenderTarget()->resourcePriv().isBudgeted() ?
bsalomoneaaaf0b2015-01-23 08:08:04 -0800685 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
686}
687
688SkSurface::Budgeted is_budgeted(SkImage* image) {
bsalomon3582d3e2015-02-13 14:20:05 -0800689 return ((SkImage_Gpu*)image)->getTexture()->resourcePriv().isBudgeted() ?
bsalomoneaaaf0b2015-01-23 08:08:04 -0800690 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
691}
692
693static void test_surface_budget(skiatest::Reporter* reporter, GrContext* context) {
694 SkImageInfo info = SkImageInfo::MakeN32Premul(8,8);
695 for (int i = 0; i < 2; ++i) {
696 SkSurface::Budgeted sbudgeted = i ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
697 for (int j = 0; j < 2; ++j) {
698 SkSurface::Budgeted ibudgeted = j ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
699 SkAutoTUnref<SkSurface>
700 surface(SkSurface::NewRenderTarget(context, sbudgeted, info, 0));
701 SkASSERT(surface);
702 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
703
mtklein31ff2982015-01-24 11:27:27 -0800704 SkAutoTUnref<SkImage> image(surface->newImageSnapshot(ibudgeted));
bsalomoneaaaf0b2015-01-23 08:08:04 -0800705
706 // Initially the image shares a texture with the surface, and the surface decides
707 // whether it is budgeted or not.
708 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
709 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(image));
710
711 // Now trigger copy-on-write
712 surface->getCanvas()->clear(SK_ColorBLUE);
713
714 // They don't share a texture anymore. They should each have made their own budget
715 // decision.
716 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
717 REPORTER_ASSERT(reporter, ibudgeted == is_budgeted(image));
718 }
719 }
720}
721
junov@chromium.orgb516a412013-05-01 22:49:59 +0000722#endif
junov@chromium.orgda904742013-05-01 22:38:16 +0000723
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000724static void TestSurfaceNoCanvas(skiatest::Reporter* reporter,
725 SurfaceType surfaceType,
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000726 GrContext* context,
727 SkSurface::ContentChangeMode mode) {
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000728 // Verifies the robustness of SkSurface for handling use cases where calls
729 // are made before a canvas is created.
730 {
731 // Test passes by not asserting
bsalomon74f681d2015-06-23 14:38:48 -0700732 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000733 SkAutoTUnref<SkSurface> aur_surface(surface);
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000734 surface->notifyContentWillChange(mode);
robertphillips@google.com03087072013-10-02 16:42:21 +0000735 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000736 }
737 {
bsalomon74f681d2015-06-23 14:38:48 -0700738 SkSurface* surface = create_surface(surfaceType, context);
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000739 SkAutoTUnref<SkSurface> aur_surface(surface);
740 SkImage* image1 = surface->newImageSnapshot();
741 SkAutoTUnref<SkImage> aur_image1(image1);
robertphillips@google.com03087072013-10-02 16:42:21 +0000742 SkDEBUGCODE(image1->validate();)
743 SkDEBUGCODE(surface->validate();)
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000744 surface->notifyContentWillChange(mode);
robertphillips@google.com03087072013-10-02 16:42:21 +0000745 SkDEBUGCODE(image1->validate();)
746 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000747 SkImage* image2 = surface->newImageSnapshot();
748 SkAutoTUnref<SkImage> aur_image2(image2);
robertphillips@google.com03087072013-10-02 16:42:21 +0000749 SkDEBUGCODE(image2->validate();)
750 SkDEBUGCODE(surface->validate();)
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000751 REPORTER_ASSERT(reporter, image1 != image2);
752 }
skia.committer@gmail.com45fb8b62013-04-17 07:00:56 +0000753
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000754}
junov@chromium.org995beb62013-03-28 13:49:22 +0000755
tfarina@chromium.org4ee16bf2014-01-10 22:08:27 +0000756DEF_GPUTEST(Surface, reporter, factory) {
reed@google.com999da9c2014-02-06 13:43:07 +0000757 test_image(reporter);
758
junov@chromium.orgaf058352013-04-03 15:03:26 +0000759 TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL);
junov@chromium.orgaf058352013-04-03 15:03:26 +0000760 TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL);
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000761 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode);
762 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000763
reedb2497c22014-12-31 12:31:43 -0800764 test_empty_image(reporter);
765 test_empty_surface(reporter, NULL);
766
reed67f2eb42014-12-10 06:54:06 -0800767 test_imagepeek(reporter, factory);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000768 test_canvaspeek(reporter, factory);
769
reed41e010c2015-06-09 12:16:53 -0700770 test_accessPixels(reporter, factory);
771
bsalomon74f681d2015-06-23 14:38:48 -0700772 test_snap_alphatype(reporter, factory);
773
junov@chromium.orgb516a412013-05-01 22:49:59 +0000774#if SK_SUPPORT_GPU
junov@chromium.orgda904742013-05-01 22:38:16 +0000775 TestGetTexture(reporter, kRaster_SurfaceType, NULL);
bsalomon49f085d2014-09-05 13:34:00 -0700776 if (factory) {
bsalomone904c092014-07-17 10:50:59 -0700777 for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
778 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
779 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
780 continue;
781 }
782 GrContext* context = factory->get(glCtxType);
bsalomon49f085d2014-09-05 13:34:00 -0700783 if (context) {
bsalomone904c092014-07-17 10:50:59 -0700784 Test_crbug263329(reporter, kGpu_SurfaceType, context);
785 Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
786 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
787 TestSurfaceCopyOnWrite(reporter, kGpuScratch_SurfaceType, context);
788 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context);
789 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpuScratch_SurfaceType, context);
790 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
791 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
792 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
793 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
794 TestGetTexture(reporter, kGpu_SurfaceType, context);
795 TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
reedb2497c22014-12-31 12:31:43 -0800796 test_empty_surface(reporter, context);
bsalomoneaaaf0b2015-01-23 08:08:04 -0800797 test_surface_budget(reporter, context);
bsalomone4579ad2015-04-08 08:38:40 -0700798 test_wrapped_texture_surface(reporter, context);
bsalomone904c092014-07-17 10:50:59 -0700799 }
robertphillips@google.com3bddb382013-11-12 13:51:03 +0000800 }
junov@chromium.orgaf058352013-04-03 15:03:26 +0000801 }
junov@chromium.org995beb62013-03-28 13:49:22 +0000802#endif
803}
reed8b26b992015-05-07 15:36:17 -0700804
805#if SK_SUPPORT_GPU
reedde499882015-06-18 13:41:40 -0700806
807struct ReleaseTextureContext {
808 ReleaseTextureContext(skiatest::Reporter* reporter) {
809 fReporter = reporter;
810 fIsReleased = false;
811 }
812
813 skiatest::Reporter* fReporter;
814 bool fIsReleased;
815
816 void doRelease() {
817 REPORTER_ASSERT(fReporter, false == fIsReleased);
818 fIsReleased = true;
819 }
820
821 static void ReleaseProc(void* context) {
822 ((ReleaseTextureContext*)context)->doRelease();
823 }
824};
825
826static SkImage* make_desc_image(GrContext* ctx, int w, int h, GrBackendObject texID,
827 ReleaseTextureContext* releaseContext) {
reed8b26b992015-05-07 15:36:17 -0700828 GrBackendTextureDesc desc;
829 desc.fConfig = kSkia8888_GrPixelConfig;
830 // need to be a rendertarget for now...
831 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
832 desc.fWidth = w;
833 desc.fHeight = h;
834 desc.fSampleCnt = 0;
835 desc.fTextureHandle = texID;
reedde499882015-06-18 13:41:40 -0700836 return releaseContext
837 ? SkImage::NewFromTexture(ctx, desc, kPremul_SkAlphaType,
838 ReleaseTextureContext::ReleaseProc, releaseContext)
839 : SkImage::NewFromTextureCopy(ctx, desc, kPremul_SkAlphaType);
reed8b26b992015-05-07 15:36:17 -0700840}
841
842static void test_image_color(skiatest::Reporter* reporter, SkImage* image, SkPMColor expected) {
843 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
844 SkPMColor pixel;
845 REPORTER_ASSERT(reporter, image->readPixels(info, &pixel, sizeof(pixel), 0, 0));
846 REPORTER_ASSERT(reporter, pixel == expected);
847}
848
849DEF_GPUTEST(SkImage_NewFromTexture, reporter, factory) {
850 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
851 if (!ctx) {
852 REPORTER_ASSERT(reporter, false);
853 return;
854 }
855 GrTextureProvider* provider = ctx->textureProvider();
856
857 const int w = 10;
858 const int h = 10;
859 SkPMColor storage[w * h];
860 const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED);
861 sk_memset32(storage, expected0, w * h);
862
863 GrSurfaceDesc desc;
864 desc.fFlags = kRenderTarget_GrSurfaceFlag; // needs to be a rendertarget for readpixels();
865 desc.fOrigin = kDefault_GrSurfaceOrigin;
866 desc.fWidth = w;
867 desc.fHeight = h;
868 desc.fConfig = kSkia8888_GrPixelConfig;
869 desc.fSampleCnt = 0;
870
871 SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, false, storage, w * 4));
872 if (!tex) {
873 REPORTER_ASSERT(reporter, false);
874 return;
875 }
reedde499882015-06-18 13:41:40 -0700876
reed8b26b992015-05-07 15:36:17 -0700877 GrBackendObject srcTex = tex->getTextureHandle();
reedde499882015-06-18 13:41:40 -0700878 ReleaseTextureContext releaseCtx(reporter);
879
880 SkAutoTUnref<SkImage> refImg(make_desc_image(ctx, w, h, srcTex, &releaseCtx));
881 SkAutoTUnref<SkImage> cpyImg(make_desc_image(ctx, w, h, srcTex, NULL));
reed8b26b992015-05-07 15:36:17 -0700882
883 test_image_color(reporter, refImg, expected0);
884 test_image_color(reporter, cpyImg, expected0);
885
886 // Now lets jam new colors into our "external" texture, and see if the images notice
887 const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE);
888 sk_memset32(storage, expected1, w * h);
889 tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp);
890
891 // We expect the ref'd image to see the new color, but cpy'd one should still see the old color
892 test_image_color(reporter, refImg, expected1);
893 test_image_color(reporter, cpyImg, expected0);
reedde499882015-06-18 13:41:40 -0700894
895 // Now exercise the release proc
896 REPORTER_ASSERT(reporter, !releaseCtx.fIsReleased);
897 refImg.reset(NULL); // force a release of the image
898 REPORTER_ASSERT(reporter, releaseCtx.fIsReleased);
reed8b26b992015-05-07 15:36:17 -0700899}
900#endif