SurfaceTest.cpp revision bda591c739001b41d77048d680f81e05723cbc05
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.allocN32Pixels(10, 10); 182 testBitmap.eraseColor(0); 183 184 SkRRect testRRect; 185 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1); 186 187 SkString testText("Hello World"); 188 const SkPoint testPoints2[] = { 189 { SkIntToScalar(0), SkIntToScalar(1) }, 190 { SkIntToScalar(1), SkIntToScalar(1) }, 191 { SkIntToScalar(2), SkIntToScalar(1) }, 192 { SkIntToScalar(3), SkIntToScalar(1) }, 193 { SkIntToScalar(4), SkIntToScalar(1) }, 194 { SkIntToScalar(5), SkIntToScalar(1) }, 195 { SkIntToScalar(6), SkIntToScalar(1) }, 196 { SkIntToScalar(7), SkIntToScalar(1) }, 197 { SkIntToScalar(8), SkIntToScalar(1) }, 198 { SkIntToScalar(9), SkIntToScalar(1) }, 199 { SkIntToScalar(10), SkIntToScalar(1) }, 200 }; 201 202#define EXPECT_COPY_ON_WRITE(command) \ 203 { \ 204 SkImage* imageBefore = surface->newImageSnapshot(); \ 205 SkAutoTUnref<SkImage> aur_before(imageBefore); \ 206 canvas-> command ; \ 207 SkImage* imageAfter = surface->newImageSnapshot(); \ 208 SkAutoTUnref<SkImage> aur_after(imageAfter); \ 209 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \ 210 } 211 212 EXPECT_COPY_ON_WRITE(clear(testColor)) 213 EXPECT_COPY_ON_WRITE(drawPaint(testPaint)) 214 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \ 215 testPaint)) 216 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint)) 217 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint)) 218 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint)) 219 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint)) 220 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0)) 221 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect)) 222 EXPECT_COPY_ON_WRITE(drawBitmapMatrix(testBitmap, testMatrix, NULL)) 223 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL)) 224 EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL)) 225 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint)) 226 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \ 227 testPaint)) 228 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \ 229 testPaint)) 230} 231 232static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter, 233 SurfaceType surfaceType, 234 GrContext* context) { 235 // This test succeeds by not triggering an assertion. 236 // The test verifies that the surface remains writable (usable) after 237 // acquiring and releasing a snapshot without triggering a copy on write. 238 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 239 SkCanvas* canvas = surface->getCanvas(); 240 canvas->clear(1); 241 surface->newImageSnapshot()->unref(); // Create and destroy SkImage 242 canvas->clear(2); // Must not assert internally 243} 244 245#if SK_SUPPORT_GPU 246static void Test_crbug263329(skiatest::Reporter* reporter, 247 GrContext* context) { 248 // This is a regression test for crbug.com/263329 249 // Bug was caused by onCopyOnWrite releasing the old surface texture 250 // back to the scratch texture pool even though the texture is used 251 // by and active SkImage_Gpu. 252 SkAutoTUnref<SkSurface> surface1(createSurface(kGpu_SurfaceType, context)); 253 SkAutoTUnref<SkSurface> surface2(createSurface(kGpu_SurfaceType, context)); 254 SkCanvas* canvas1 = surface1->getCanvas(); 255 SkCanvas* canvas2 = surface2->getCanvas(); 256 canvas1->clear(1); 257 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot()); 258 // Trigger copy on write, new backing is a scratch texture 259 canvas1->clear(2); 260 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot()); 261 // Trigger copy on write, old backing should not be returned to scratch 262 // pool because it is held by image2 263 canvas1->clear(3); 264 265 canvas2->clear(4); 266 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot()); 267 // Trigger copy on write on surface2. The new backing store should not 268 // be recycling a texture that is held by an existing image. 269 canvas2->clear(5); 270 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot()); 271 REPORTER_ASSERT(reporter, image4->getTexture() != image3->getTexture()); 272 // The following assertion checks crbug.com/263329 273 REPORTER_ASSERT(reporter, image4->getTexture() != image2->getTexture()); 274 REPORTER_ASSERT(reporter, image4->getTexture() != image1->getTexture()); 275 REPORTER_ASSERT(reporter, image3->getTexture() != image2->getTexture()); 276 REPORTER_ASSERT(reporter, image3->getTexture() != image1->getTexture()); 277 REPORTER_ASSERT(reporter, image2->getTexture() != image1->getTexture()); 278} 279 280static void TestGetTexture(skiatest::Reporter* reporter, 281 SurfaceType surfaceType, 282 GrContext* context) { 283 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 284 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 285 GrTexture* texture = image->getTexture(); 286 if (surfaceType == kGpu_SurfaceType) { 287 REPORTER_ASSERT(reporter, NULL != texture); 288 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle()); 289 } else { 290 REPORTER_ASSERT(reporter, NULL == texture); 291 } 292 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); 293 REPORTER_ASSERT(reporter, image->getTexture() == texture); 294} 295#endif 296 297static void TestSurfaceNoCanvas(skiatest::Reporter* reporter, 298 SurfaceType surfaceType, 299 GrContext* context, 300 SkSurface::ContentChangeMode mode) { 301 // Verifies the robustness of SkSurface for handling use cases where calls 302 // are made before a canvas is created. 303 { 304 // Test passes by not asserting 305 SkSurface* surface = createSurface(surfaceType, context); 306 SkAutoTUnref<SkSurface> aur_surface(surface); 307 surface->notifyContentWillChange(mode); 308 SkDEBUGCODE(surface->validate();) 309 } 310 { 311 SkSurface* surface = createSurface(surfaceType, context); 312 SkAutoTUnref<SkSurface> aur_surface(surface); 313 SkImage* image1 = surface->newImageSnapshot(); 314 SkAutoTUnref<SkImage> aur_image1(image1); 315 SkDEBUGCODE(image1->validate();) 316 SkDEBUGCODE(surface->validate();) 317 surface->notifyContentWillChange(mode); 318 SkDEBUGCODE(image1->validate();) 319 SkDEBUGCODE(surface->validate();) 320 SkImage* image2 = surface->newImageSnapshot(); 321 SkAutoTUnref<SkImage> aur_image2(image2); 322 SkDEBUGCODE(image2->validate();) 323 SkDEBUGCODE(surface->validate();) 324 REPORTER_ASSERT(reporter, image1 != image2); 325 } 326 327} 328 329DEF_GPUTEST(Surface, reporter, factory) { 330 test_image(reporter); 331 332 TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL); 333 TestSurfaceCopyOnWrite(reporter, kPicture_SurfaceType, NULL); 334 TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL); 335 TestSurfaceWritableAfterSnapshotRelease(reporter, kPicture_SurfaceType, NULL); 336 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode); 337 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode); 338 test_imagepeek(reporter); 339#if SK_SUPPORT_GPU 340 TestGetTexture(reporter, kRaster_SurfaceType, NULL); 341 TestGetTexture(reporter, kPicture_SurfaceType, NULL); 342 if (NULL != factory) { 343 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType); 344 if (NULL != context) { 345 Test_crbug263329(reporter, context); 346 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context); 347 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context); 348 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode); 349 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode); 350 TestGetTexture(reporter, kGpu_SurfaceType, context); 351 } 352 } 353#endif 354} 355