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