1 2 /* 3 * Copyright 2013 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SkCanvas.h" 9 #include "SkRRect.h" 10 #include "SkSurface.h" 11 #include "Test.h" 12 13 #if SK_SUPPORT_GPU 14 #include "GrContextFactory.h" 15 #else 16 class GrContextFactory; 17 class GrContext; 18 #endif 19 20 enum SurfaceType { 21 kRaster_SurfaceType, 22 kGpu_SurfaceType, 23 kPicture_SurfaceType 24 }; 25 26 static SkSurface* createSurface(SurfaceType surfaceType, GrContext* context) { 27 static const SkImageInfo imageSpec = { 28 10, // width 29 10, // height 30 kPMColor_SkColorType, 31 kPremul_SkAlphaType 32 }; 33 34 switch (surfaceType) { 35 case kRaster_SurfaceType: 36 return SkSurface::NewRaster(imageSpec); 37 case kGpu_SurfaceType: 38 #if SK_SUPPORT_GPU 39 SkASSERT(NULL != context); 40 return SkSurface::NewRenderTarget(context, imageSpec); 41 #else 42 SkASSERT(0); 43 #endif 44 case kPicture_SurfaceType: 45 return SkSurface::NewPicture(10, 10); 46 } 47 SkASSERT(0); 48 return NULL; 49 } 50 51 static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType, 52 GrContext* context) { 53 // Verify that the right canvas commands trigger a copy on write 54 SkSurface* surface = createSurface(surfaceType, context); 55 SkAutoTUnref<SkSurface> aur_surface(surface); 56 SkCanvas* canvas = surface->getCanvas(); 57 58 const SkRect testRect = 59 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 60 SkIntToScalar(4), SkIntToScalar(5)); 61 SkMatrix testMatrix; 62 testMatrix.reset(); 63 testMatrix.setScale(SkIntToScalar(2), SkIntToScalar(3)); 64 65 SkPath testPath; 66 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 67 SkIntToScalar(2), SkIntToScalar(1))); 68 69 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1); 70 71 SkRegion testRegion; 72 testRegion.setRect(testIRect); 73 74 75 const SkColor testColor = 0x01020304; 76 const SkPaint testPaint; 77 const SkPoint testPoints[3] = { 78 {SkIntToScalar(0), SkIntToScalar(0)}, 79 {SkIntToScalar(2), SkIntToScalar(1)}, 80 {SkIntToScalar(0), SkIntToScalar(2)} 81 }; 82 const size_t testPointCount = 3; 83 84 SkBitmap testBitmap; 85 testBitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10); 86 testBitmap.allocPixels(); 87 testBitmap.eraseColor(0); 88 89 SkRRect testRRect; 90 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1); 91 92 SkString testText("Hello World"); 93 const SkPoint testPoints2[] = { 94 { SkIntToScalar(0), SkIntToScalar(1) }, 95 { SkIntToScalar(1), SkIntToScalar(1) }, 96 { SkIntToScalar(2), SkIntToScalar(1) }, 97 { SkIntToScalar(3), SkIntToScalar(1) }, 98 { SkIntToScalar(4), SkIntToScalar(1) }, 99 { SkIntToScalar(5), SkIntToScalar(1) }, 100 { SkIntToScalar(6), SkIntToScalar(1) }, 101 { SkIntToScalar(7), SkIntToScalar(1) }, 102 { SkIntToScalar(8), SkIntToScalar(1) }, 103 { SkIntToScalar(9), SkIntToScalar(1) }, 104 { SkIntToScalar(10), SkIntToScalar(1) }, 105 }; 106 107 #define EXPECT_COPY_ON_WRITE(command) \ 108 { \ 109 SkImage* imageBefore = surface->newImageSnapshot(); \ 110 SkAutoTUnref<SkImage> aur_before(imageBefore); \ 111 canvas-> command ; \ 112 SkImage* imageAfter = surface->newImageSnapshot(); \ 113 SkAutoTUnref<SkImage> aur_after(imageAfter); \ 114 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \ 115 } 116 117 EXPECT_COPY_ON_WRITE(clear(testColor)) 118 EXPECT_COPY_ON_WRITE(drawPaint(testPaint)) 119 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \ 120 testPaint)) 121 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint)) 122 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint)) 123 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint)) 124 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint)) 125 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0)) 126 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect)) 127 EXPECT_COPY_ON_WRITE(drawBitmapMatrix(testBitmap, testMatrix, NULL)) 128 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL)) 129 EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL)) 130 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint)) 131 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \ 132 testPaint)) 133 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \ 134 testPaint)) 135 } 136 137 static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter, 138 SurfaceType surfaceType, 139 GrContext* context) { 140 // This test succeeds by not triggering an assertion. 141 // The test verifies that the surface remains writable (usable) after 142 // acquiring and releasing a snapshot without triggering a copy on write. 143 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 144 SkCanvas* canvas = surface->getCanvas(); 145 canvas->clear(1); 146 surface->newImageSnapshot()->unref(); // Create and destroy SkImage 147 canvas->clear(2); // Must not assert internally 148 } 149 150 #if SK_SUPPORT_GPU 151 static void Test_crbug263329(skiatest::Reporter* reporter, 152 GrContext* context) { 153 // This is a regression test for crbug.com/263329 154 // Bug was caused by onCopyOnWrite releasing the old surface texture 155 // back to the scratch texture pool even though the texture is used 156 // by and active SkImage_Gpu. 157 SkAutoTUnref<SkSurface> surface1(createSurface(kGpu_SurfaceType, context)); 158 SkAutoTUnref<SkSurface> surface2(createSurface(kGpu_SurfaceType, context)); 159 SkCanvas* canvas1 = surface1->getCanvas(); 160 SkCanvas* canvas2 = surface2->getCanvas(); 161 canvas1->clear(1); 162 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot()); 163 // Trigger copy on write, new backing is a scratch texture 164 canvas1->clear(2); 165 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot()); 166 // Trigger copy on write, old backing should not be returned to scratch 167 // pool because it is held by image2 168 canvas1->clear(3); 169 170 canvas2->clear(4); 171 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot()); 172 // Trigger copy on write on surface2. The new backing store should not 173 // be recycling a texture that is held by an existing image. 174 canvas2->clear(5); 175 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot()); 176 REPORTER_ASSERT(reporter, image4->getTexture() != image3->getTexture()); 177 // The following assertion checks crbug.com/263329 178 REPORTER_ASSERT(reporter, image4->getTexture() != image2->getTexture()); 179 REPORTER_ASSERT(reporter, image4->getTexture() != image1->getTexture()); 180 REPORTER_ASSERT(reporter, image3->getTexture() != image2->getTexture()); 181 REPORTER_ASSERT(reporter, image3->getTexture() != image1->getTexture()); 182 REPORTER_ASSERT(reporter, image2->getTexture() != image1->getTexture()); 183 } 184 185 static void TestGetTexture(skiatest::Reporter* reporter, 186 SurfaceType surfaceType, 187 GrContext* context) { 188 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 189 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 190 GrTexture* texture = image->getTexture(); 191 if (surfaceType == kGpu_SurfaceType) { 192 REPORTER_ASSERT(reporter, NULL != texture); 193 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle()); 194 } else { 195 REPORTER_ASSERT(reporter, NULL == texture); 196 } 197 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); 198 REPORTER_ASSERT(reporter, image->getTexture() == texture); 199 } 200 #endif 201 202 static void TestSurfaceNoCanvas(skiatest::Reporter* reporter, 203 SurfaceType surfaceType, 204 GrContext* context, 205 SkSurface::ContentChangeMode mode) { 206 // Verifies the robustness of SkSurface for handling use cases where calls 207 // are made before a canvas is created. 208 { 209 // Test passes by not asserting 210 SkSurface* surface = createSurface(surfaceType, context); 211 SkAutoTUnref<SkSurface> aur_surface(surface); 212 surface->notifyContentWillChange(mode); 213 SkDEBUGCODE(surface->validate();) 214 } 215 { 216 SkSurface* surface = createSurface(surfaceType, context); 217 SkAutoTUnref<SkSurface> aur_surface(surface); 218 SkImage* image1 = surface->newImageSnapshot(); 219 SkAutoTUnref<SkImage> aur_image1(image1); 220 SkDEBUGCODE(image1->validate();) 221 SkDEBUGCODE(surface->validate();) 222 surface->notifyContentWillChange(mode); 223 SkDEBUGCODE(image1->validate();) 224 SkDEBUGCODE(surface->validate();) 225 SkImage* image2 = surface->newImageSnapshot(); 226 SkAutoTUnref<SkImage> aur_image2(image2); 227 SkDEBUGCODE(image2->validate();) 228 SkDEBUGCODE(surface->validate();) 229 REPORTER_ASSERT(reporter, image1 != image2); 230 } 231 232 } 233 234 static void TestSurface(skiatest::Reporter* reporter, GrContextFactory* factory) { 235 TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL); 236 TestSurfaceCopyOnWrite(reporter, kPicture_SurfaceType, NULL); 237 TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL); 238 TestSurfaceWritableAfterSnapshotRelease(reporter, kPicture_SurfaceType, NULL); 239 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode); 240 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode); 241 #if SK_SUPPORT_GPU 242 TestGetTexture(reporter, kRaster_SurfaceType, NULL); 243 TestGetTexture(reporter, kPicture_SurfaceType, NULL); 244 if (NULL != factory) { 245 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType); 246 if (NULL != context) { 247 Test_crbug263329(reporter, context); 248 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context); 249 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context); 250 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode); 251 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode); 252 TestGetTexture(reporter, kGpu_SurfaceType, context); 253 } 254 } 255 #endif 256 } 257 258 #include "TestClassDef.h" 259 DEFINE_GPUTESTCLASS("Surface", SurfaceTestClass, TestSurface) 260