1 /* 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 */ 7 8 #include "SkCanvas.h" 9 #include "SkData.h" 10 #include "SkDecodingImageGenerator.h" 11 #include "SkImageEncoder.h" 12 #include "SkRRect.h" 13 #include "SkSurface.h" 14 #include "SkUtils.h" 15 #include "Test.h" 16 17 #if SK_SUPPORT_GPU 18 #include "GrContextFactory.h" 19 #else 20 class GrContextFactory; 21 class GrContext; 22 #endif 23 24 enum SurfaceType { 25 kRaster_SurfaceType, 26 kRasterDirect_SurfaceType, 27 kGpu_SurfaceType, 28 kGpuScratch_SurfaceType, 29 }; 30 31 static void release_storage(void* pixels, void* context) { 32 SkASSERT(pixels == context); 33 sk_free(pixels); 34 } 35 36 static SkSurface* createSurface(SurfaceType surfaceType, GrContext* context, 37 SkImageInfo* requestedInfo = NULL) { 38 static const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); 39 40 if (requestedInfo) { 41 *requestedInfo = info; 42 } 43 44 switch (surfaceType) { 45 case kRaster_SurfaceType: 46 return SkSurface::NewRaster(info); 47 case kRasterDirect_SurfaceType: { 48 const size_t rowBytes = info.minRowBytes(); 49 void* storage = sk_malloc_throw(info.getSafeSize(rowBytes)); 50 return SkSurface::NewRasterDirectReleaseProc(info, storage, rowBytes, 51 release_storage, storage); 52 } 53 case kGpu_SurfaceType: 54 #if SK_SUPPORT_GPU 55 return context ? SkSurface::NewRenderTarget(context, info, 0, NULL) : NULL; 56 #endif 57 break; 58 case kGpuScratch_SurfaceType: 59 #if SK_SUPPORT_GPU 60 return context ? SkSurface::NewScratchRenderTarget(context, info) : NULL; 61 #endif 62 break; 63 } 64 return NULL; 65 } 66 67 enum ImageType { 68 kRasterCopy_ImageType, 69 kRasterData_ImageType, 70 kGpu_ImageType, 71 kCodec_ImageType, 72 }; 73 74 static void test_image(skiatest::Reporter* reporter) { 75 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 76 size_t rowBytes = info.minRowBytes(); 77 size_t size = info.getSafeSize(rowBytes); 78 SkData* data = SkData::NewUninitialized(size); 79 80 REPORTER_ASSERT(reporter, 1 == data->getRefCnt()); 81 SkImage* image = SkImage::NewRasterData(info, data, rowBytes); 82 REPORTER_ASSERT(reporter, 2 == data->getRefCnt()); 83 image->unref(); 84 REPORTER_ASSERT(reporter, 1 == data->getRefCnt()); 85 data->unref(); 86 } 87 88 static SkImage* createImage(ImageType imageType, GrContext* context, 89 SkColor color) { 90 const SkPMColor pmcolor = SkPreMultiplyColor(color); 91 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); 92 const size_t rowBytes = info.minRowBytes(); 93 const size_t size = rowBytes * info.height(); 94 95 SkAutoTUnref<SkData> data(SkData::NewUninitialized(size)); 96 void* addr = data->writable_data(); 97 sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2)); 98 99 switch (imageType) { 100 case kRasterCopy_ImageType: 101 return SkImage::NewRasterCopy(info, addr, rowBytes); 102 case kRasterData_ImageType: 103 return SkImage::NewRasterData(info, data, rowBytes); 104 case kGpu_ImageType: 105 return NULL; // TODO 106 case kCodec_ImageType: { 107 SkBitmap bitmap; 108 bitmap.installPixels(info, addr, rowBytes); 109 SkAutoTUnref<SkData> src( 110 SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 111 100)); 112 return SkImage::NewFromGenerator( 113 SkDecodingImageGenerator::Create(data, SkDecodingImageGenerator::Options())); 114 } 115 } 116 SkASSERT(false); 117 return NULL; 118 } 119 120 static void test_imagepeek(skiatest::Reporter* reporter) { 121 static const struct { 122 ImageType fType; 123 bool fPeekShouldSucceed; 124 } gRec[] = { 125 { kRasterCopy_ImageType, true }, 126 { kRasterData_ImageType, true }, 127 { kGpu_ImageType, false }, 128 { kCodec_ImageType, false }, 129 }; 130 131 const SkColor color = SK_ColorRED; 132 const SkPMColor pmcolor = SkPreMultiplyColor(color); 133 134 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 135 SkImageInfo info; 136 size_t rowBytes; 137 138 SkAutoTUnref<SkImage> image(createImage(gRec[i].fType, NULL, color)); 139 if (!image.get()) { 140 continue; // gpu may not be enabled 141 } 142 const void* addr = image->peekPixels(&info, &rowBytes); 143 bool success = SkToBool(addr); 144 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success); 145 if (success) { 146 REPORTER_ASSERT(reporter, 10 == info.width()); 147 REPORTER_ASSERT(reporter, 10 == info.height()); 148 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType()); 149 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() || 150 kOpaque_SkAlphaType == info.alphaType()); 151 REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes); 152 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr); 153 } 154 } 155 } 156 157 static void test_canvaspeek(skiatest::Reporter* reporter, 158 GrContextFactory* factory) { 159 static const struct { 160 SurfaceType fType; 161 bool fPeekShouldSucceed; 162 } gRec[] = { 163 { kRaster_SurfaceType, true }, 164 { kRasterDirect_SurfaceType, true }, 165 #if SK_SUPPORT_GPU 166 { kGpu_SurfaceType, false }, 167 { kGpuScratch_SurfaceType, false }, 168 #endif 169 }; 170 171 const SkColor color = SK_ColorRED; 172 const SkPMColor pmcolor = SkPreMultiplyColor(color); 173 174 int cnt; 175 #if SK_SUPPORT_GPU 176 cnt = GrContextFactory::kGLContextTypeCnt; 177 #else 178 cnt = 1; 179 #endif 180 181 for (int i= 0; i < cnt; ++i) { 182 GrContext* context = NULL; 183 #if SK_SUPPORT_GPU 184 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i; 185 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) { 186 continue; 187 } 188 context = factory->get(glCtxType); 189 190 if (NULL == context) { 191 continue; 192 } 193 #endif 194 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 195 SkImageInfo info, requestInfo; 196 size_t rowBytes; 197 198 SkAutoTUnref<SkSurface> surface(createSurface(gRec[i].fType, context, 199 &requestInfo)); 200 surface->getCanvas()->clear(color); 201 202 const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes); 203 bool success = SkToBool(addr); 204 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success); 205 206 SkImageInfo info2; 207 size_t rb2; 208 const void* addr2 = surface->peekPixels(&info2, &rb2); 209 210 if (success) { 211 REPORTER_ASSERT(reporter, requestInfo == info); 212 REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes); 213 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr); 214 215 REPORTER_ASSERT(reporter, addr2 == addr); 216 REPORTER_ASSERT(reporter, info2 == info); 217 REPORTER_ASSERT(reporter, rb2 == rowBytes); 218 } else { 219 REPORTER_ASSERT(reporter, NULL == addr2); 220 } 221 } 222 } 223 } 224 225 static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType, 226 GrContext* context) { 227 // Verify that the right canvas commands trigger a copy on write 228 SkSurface* surface = createSurface(surfaceType, context); 229 SkAutoTUnref<SkSurface> aur_surface(surface); 230 SkCanvas* canvas = surface->getCanvas(); 231 232 const SkRect testRect = 233 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 234 SkIntToScalar(4), SkIntToScalar(5)); 235 SkMatrix testMatrix; 236 testMatrix.reset(); 237 testMatrix.setScale(SkIntToScalar(2), SkIntToScalar(3)); 238 239 SkPath testPath; 240 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 241 SkIntToScalar(2), SkIntToScalar(1))); 242 243 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1); 244 245 SkRegion testRegion; 246 testRegion.setRect(testIRect); 247 248 249 const SkColor testColor = 0x01020304; 250 const SkPaint testPaint; 251 const SkPoint testPoints[3] = { 252 {SkIntToScalar(0), SkIntToScalar(0)}, 253 {SkIntToScalar(2), SkIntToScalar(1)}, 254 {SkIntToScalar(0), SkIntToScalar(2)} 255 }; 256 const size_t testPointCount = 3; 257 258 SkBitmap testBitmap; 259 testBitmap.allocN32Pixels(10, 10); 260 testBitmap.eraseColor(0); 261 262 SkRRect testRRect; 263 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1); 264 265 SkString testText("Hello World"); 266 const SkPoint testPoints2[] = { 267 { SkIntToScalar(0), SkIntToScalar(1) }, 268 { SkIntToScalar(1), SkIntToScalar(1) }, 269 { SkIntToScalar(2), SkIntToScalar(1) }, 270 { SkIntToScalar(3), SkIntToScalar(1) }, 271 { SkIntToScalar(4), SkIntToScalar(1) }, 272 { SkIntToScalar(5), SkIntToScalar(1) }, 273 { SkIntToScalar(6), SkIntToScalar(1) }, 274 { SkIntToScalar(7), SkIntToScalar(1) }, 275 { SkIntToScalar(8), SkIntToScalar(1) }, 276 { SkIntToScalar(9), SkIntToScalar(1) }, 277 { SkIntToScalar(10), SkIntToScalar(1) }, 278 }; 279 280 #define EXPECT_COPY_ON_WRITE(command) \ 281 { \ 282 SkImage* imageBefore = surface->newImageSnapshot(); \ 283 SkAutoTUnref<SkImage> aur_before(imageBefore); \ 284 canvas-> command ; \ 285 SkImage* imageAfter = surface->newImageSnapshot(); \ 286 SkAutoTUnref<SkImage> aur_after(imageAfter); \ 287 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \ 288 } 289 290 EXPECT_COPY_ON_WRITE(clear(testColor)) 291 EXPECT_COPY_ON_WRITE(drawPaint(testPaint)) 292 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \ 293 testPaint)) 294 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint)) 295 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint)) 296 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint)) 297 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint)) 298 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0)) 299 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect)) 300 EXPECT_COPY_ON_WRITE(drawBitmapMatrix(testBitmap, testMatrix, NULL)) 301 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL)) 302 EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL)) 303 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint)) 304 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \ 305 testPaint)) 306 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \ 307 testPaint)) 308 } 309 310 static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter, 311 SurfaceType surfaceType, 312 GrContext* context) { 313 // This test succeeds by not triggering an assertion. 314 // The test verifies that the surface remains writable (usable) after 315 // acquiring and releasing a snapshot without triggering a copy on write. 316 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 317 SkCanvas* canvas = surface->getCanvas(); 318 canvas->clear(1); 319 surface->newImageSnapshot()->unref(); // Create and destroy SkImage 320 canvas->clear(2); // Must not assert internally 321 } 322 323 #if SK_SUPPORT_GPU 324 static void TestSurfaceInCache(skiatest::Reporter* reporter, 325 SurfaceType surfaceType, 326 GrContext* context) { 327 context->freeGpuResources(); 328 int resourceCount; 329 330 context->getResourceCacheUsage(&resourceCount, NULL); 331 REPORTER_ASSERT(reporter, 0 == resourceCount); 332 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 333 // Note: the stencil buffer is always cached, so kGpu_SurfaceType uses 334 // one cached resource, and kGpuScratch_SurfaceType uses two. 335 int expectedCachedResources = surfaceType == kGpuScratch_SurfaceType ? 2 : 1; 336 context->getResourceCacheUsage(&resourceCount, NULL); 337 REPORTER_ASSERT(reporter, expectedCachedResources == resourceCount); 338 339 // Verify that all the cached resources are locked in cache. 340 context->freeGpuResources(); 341 context->getResourceCacheUsage(&resourceCount, NULL); 342 REPORTER_ASSERT(reporter, expectedCachedResources == resourceCount); 343 344 // Verify that all the cached resources are unlocked upon surface release 345 surface.reset(0); 346 context->freeGpuResources(); 347 context->getResourceCacheUsage(&resourceCount, NULL); 348 REPORTER_ASSERT(reporter, 0 == resourceCount); 349 } 350 351 static void Test_crbug263329(skiatest::Reporter* reporter, 352 SurfaceType surfaceType, 353 GrContext* context) { 354 // This is a regression test for crbug.com/263329 355 // Bug was caused by onCopyOnWrite releasing the old surface texture 356 // back to the scratch texture pool even though the texture is used 357 // by and active SkImage_Gpu. 358 SkAutoTUnref<SkSurface> surface1(createSurface(surfaceType, context)); 359 SkAutoTUnref<SkSurface> surface2(createSurface(surfaceType, context)); 360 SkCanvas* canvas1 = surface1->getCanvas(); 361 SkCanvas* canvas2 = surface2->getCanvas(); 362 canvas1->clear(1); 363 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot()); 364 // Trigger copy on write, new backing is a scratch texture 365 canvas1->clear(2); 366 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot()); 367 // Trigger copy on write, old backing should not be returned to scratch 368 // pool because it is held by image2 369 canvas1->clear(3); 370 371 canvas2->clear(4); 372 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot()); 373 // Trigger copy on write on surface2. The new backing store should not 374 // be recycling a texture that is held by an existing image. 375 canvas2->clear(5); 376 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot()); 377 REPORTER_ASSERT(reporter, image4->getTexture() != image3->getTexture()); 378 // The following assertion checks crbug.com/263329 379 REPORTER_ASSERT(reporter, image4->getTexture() != image2->getTexture()); 380 REPORTER_ASSERT(reporter, image4->getTexture() != image1->getTexture()); 381 REPORTER_ASSERT(reporter, image3->getTexture() != image2->getTexture()); 382 REPORTER_ASSERT(reporter, image3->getTexture() != image1->getTexture()); 383 REPORTER_ASSERT(reporter, image2->getTexture() != image1->getTexture()); 384 } 385 386 static void TestGetTexture(skiatest::Reporter* reporter, 387 SurfaceType surfaceType, 388 GrContext* context) { 389 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 390 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 391 GrTexture* texture = image->getTexture(); 392 if (surfaceType == kGpu_SurfaceType || surfaceType == kGpuScratch_SurfaceType) { 393 REPORTER_ASSERT(reporter, texture); 394 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle()); 395 } else { 396 REPORTER_ASSERT(reporter, NULL == texture); 397 } 398 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); 399 REPORTER_ASSERT(reporter, image->getTexture() == texture); 400 } 401 #endif 402 403 static void TestSurfaceNoCanvas(skiatest::Reporter* reporter, 404 SurfaceType surfaceType, 405 GrContext* context, 406 SkSurface::ContentChangeMode mode) { 407 // Verifies the robustness of SkSurface for handling use cases where calls 408 // are made before a canvas is created. 409 { 410 // Test passes by not asserting 411 SkSurface* surface = createSurface(surfaceType, context); 412 SkAutoTUnref<SkSurface> aur_surface(surface); 413 surface->notifyContentWillChange(mode); 414 SkDEBUGCODE(surface->validate();) 415 } 416 { 417 SkSurface* surface = createSurface(surfaceType, context); 418 SkAutoTUnref<SkSurface> aur_surface(surface); 419 SkImage* image1 = surface->newImageSnapshot(); 420 SkAutoTUnref<SkImage> aur_image1(image1); 421 SkDEBUGCODE(image1->validate();) 422 SkDEBUGCODE(surface->validate();) 423 surface->notifyContentWillChange(mode); 424 SkDEBUGCODE(image1->validate();) 425 SkDEBUGCODE(surface->validate();) 426 SkImage* image2 = surface->newImageSnapshot(); 427 SkAutoTUnref<SkImage> aur_image2(image2); 428 SkDEBUGCODE(image2->validate();) 429 SkDEBUGCODE(surface->validate();) 430 REPORTER_ASSERT(reporter, image1 != image2); 431 } 432 433 } 434 435 DEF_GPUTEST(Surface, reporter, factory) { 436 test_image(reporter); 437 438 TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL); 439 TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL); 440 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode); 441 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode); 442 443 test_imagepeek(reporter); 444 test_canvaspeek(reporter, factory); 445 446 #if SK_SUPPORT_GPU 447 TestGetTexture(reporter, kRaster_SurfaceType, NULL); 448 if (factory) { 449 for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) { 450 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i; 451 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) { 452 continue; 453 } 454 GrContext* context = factory->get(glCtxType); 455 if (context) { 456 TestSurfaceInCache(reporter, kGpu_SurfaceType, context); 457 TestSurfaceInCache(reporter, kGpuScratch_SurfaceType, context); 458 Test_crbug263329(reporter, kGpu_SurfaceType, context); 459 Test_crbug263329(reporter, kGpuScratch_SurfaceType, context); 460 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context); 461 TestSurfaceCopyOnWrite(reporter, kGpuScratch_SurfaceType, context); 462 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context); 463 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpuScratch_SurfaceType, context); 464 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode); 465 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode); 466 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode); 467 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kRetain_ContentChangeMode); 468 TestGetTexture(reporter, kGpu_SurfaceType, context); 469 TestGetTexture(reporter, kGpuScratch_SurfaceType, context); 470 } 471 } 472 } 473 #endif 474 } 475