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