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 16class GrContextFactory; 17class GrContext; 18#endif 19 20enum SurfaceType { 21 kRaster_SurfaceType, 22 kGpu_SurfaceType, 23 kPicture_SurfaceType 24}; 25 26static SkSurface* createSurface(SurfaceType surfaceType, GrContext* context) { 27 static const SkImage::Info imageSpec = { 28 10, // width 29 10, // height 30 SkImage::kPMColor_ColorType, 31 SkImage::kPremul_AlphaType 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 51static 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 88 SkRRect testRRect; 89 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1); 90 91 SkString testText("Hello World"); 92 const SkPoint testPoints2[] = { 93 { SkIntToScalar(0), SkIntToScalar(1) }, 94 { SkIntToScalar(1), SkIntToScalar(1) }, 95 { SkIntToScalar(2), SkIntToScalar(1) }, 96 { SkIntToScalar(3), SkIntToScalar(1) }, 97 { SkIntToScalar(4), SkIntToScalar(1) }, 98 { SkIntToScalar(5), SkIntToScalar(1) }, 99 { SkIntToScalar(6), SkIntToScalar(1) }, 100 { SkIntToScalar(7), SkIntToScalar(1) }, 101 { SkIntToScalar(8), SkIntToScalar(1) }, 102 { SkIntToScalar(9), SkIntToScalar(1) }, 103 { SkIntToScalar(10), SkIntToScalar(1) }, 104 }; 105 106#define EXPECT_COPY_ON_WRITE(command) \ 107 { \ 108 SkImage* imageBefore = surface->newImageSnapshot(); \ 109 SkAutoTUnref<SkImage> aur_before(imageBefore); \ 110 canvas-> command ; \ 111 SkImage* imageAfter = surface->newImageSnapshot(); \ 112 SkAutoTUnref<SkImage> aur_after(imageAfter); \ 113 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \ 114 } 115 116 EXPECT_COPY_ON_WRITE(clear(testColor)) 117 EXPECT_COPY_ON_WRITE(drawPaint(testPaint)) 118 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \ 119 testPaint)) 120 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint)) 121 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint)) 122 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint)) 123 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint)) 124 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0)) 125 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect)) 126 EXPECT_COPY_ON_WRITE(drawBitmapMatrix(testBitmap, testMatrix, NULL)) 127 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL)) 128 EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL)) 129 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint)) 130 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \ 131 testPaint)) 132 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \ 133 testPaint)) 134} 135 136static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter, 137 SurfaceType surfaceType, 138 GrContext* context) { 139 // This test succeeds by not triggering an assertion. 140 // The test verifies that the surface remains writable (usable) after 141 // acquiring and releasing a snapshot without triggering a copy on write. 142 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 143 SkCanvas* canvas = surface->getCanvas(); 144 canvas->clear(1); 145 surface->newImageSnapshot()->unref(); // Create and destroy SkImage 146 canvas->clear(2); // Must not assert internally 147} 148 149#if SK_SUPPORT_GPU 150static void Test_crbug263329(skiatest::Reporter* reporter, 151 GrContext* context) { 152 // This is a regression test for crbug.com/263329 153 // Bug was caused by onCopyOnWrite releasing the old surface texture 154 // back to the scratch texture pool even though the texture is used 155 // by and active SkImage_Gpu. 156 SkAutoTUnref<SkSurface> surface1(createSurface(kGpu_SurfaceType, context)); 157 SkAutoTUnref<SkSurface> surface2(createSurface(kGpu_SurfaceType, context)); 158 SkCanvas* canvas1 = surface1->getCanvas(); 159 SkCanvas* canvas2 = surface2->getCanvas(); 160 canvas1->clear(1); 161 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot()); 162 // Trigger copy on write, new backing is a scratch texture 163 canvas1->clear(2); 164 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot()); 165 // Trigger copy on write, old backing should not be returned to scratch 166 // pool because it is held by image2 167 canvas1->clear(3); 168 169 canvas2->clear(4); 170 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot()); 171 // Trigger copy on write on surface2. The new backing store should not 172 // be recycling a texture that is held by an existing image. 173 canvas2->clear(5); 174 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot()); 175 REPORTER_ASSERT(reporter, image4->getTexture() != image3->getTexture()); 176 // The following assertion checks crbug.com/263329 177 REPORTER_ASSERT(reporter, image4->getTexture() != image2->getTexture()); 178 REPORTER_ASSERT(reporter, image4->getTexture() != image1->getTexture()); 179 REPORTER_ASSERT(reporter, image3->getTexture() != image2->getTexture()); 180 REPORTER_ASSERT(reporter, image3->getTexture() != image1->getTexture()); 181 REPORTER_ASSERT(reporter, image2->getTexture() != image1->getTexture()); 182} 183 184static void TestGetTexture(skiatest::Reporter* reporter, 185 SurfaceType surfaceType, 186 GrContext* context) { 187 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 188 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 189 GrTexture* texture = image->getTexture(); 190 if (surfaceType == kGpu_SurfaceType) { 191 REPORTER_ASSERT(reporter, NULL != texture); 192 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle()); 193 } else { 194 REPORTER_ASSERT(reporter, NULL == texture); 195 } 196 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); 197 REPORTER_ASSERT(reporter, image->getTexture() == texture); 198} 199#endif 200 201static void TestSurfaceNoCanvas(skiatest::Reporter* reporter, 202 SurfaceType surfaceType, 203 GrContext* context, 204 SkSurface::ContentChangeMode mode) { 205 // Verifies the robustness of SkSurface for handling use cases where calls 206 // are made before a canvas is created. 207 { 208 // Test passes by not asserting 209 SkSurface* surface = createSurface(surfaceType, context); 210 SkAutoTUnref<SkSurface> aur_surface(surface); 211 surface->notifyContentWillChange(mode); 212 surface->validate(); 213 } 214 { 215 SkSurface* surface = createSurface(surfaceType, context); 216 SkAutoTUnref<SkSurface> aur_surface(surface); 217 SkImage* image1 = surface->newImageSnapshot(); 218 SkAutoTUnref<SkImage> aur_image1(image1); 219 image1->validate(); 220 surface->validate(); 221 surface->notifyContentWillChange(mode); 222 image1->validate(); 223 surface->validate(); 224 SkImage* image2 = surface->newImageSnapshot(); 225 SkAutoTUnref<SkImage> aur_image2(image2); 226 image2->validate(); 227 surface->validate(); 228 REPORTER_ASSERT(reporter, image1 != image2); 229 } 230 231} 232 233static void TestSurface(skiatest::Reporter* reporter, GrContextFactory* factory) { 234 TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL); 235 TestSurfaceCopyOnWrite(reporter, kPicture_SurfaceType, NULL); 236 TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL); 237 TestSurfaceWritableAfterSnapshotRelease(reporter, kPicture_SurfaceType, NULL); 238 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode); 239 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode); 240#if SK_SUPPORT_GPU 241 TestGetTexture(reporter, kRaster_SurfaceType, NULL); 242 TestGetTexture(reporter, kPicture_SurfaceType, NULL); 243 if (NULL != factory) { 244 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType); 245 Test_crbug263329(reporter, context); 246 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context); 247 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context); 248 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode); 249 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode); 250 TestGetTexture(reporter, kGpu_SurfaceType, context); 251 } 252#endif 253} 254 255#include "TestClassDef.h" 256DEFINE_GPUTESTCLASS("Surface", SurfaceTestClass, TestSurface) 257