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