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 19 class GrContextFactory; 20 class GrContext; 21 #endif 22 23 enum SurfaceType { 24 kRaster_SurfaceType, 25 kRasterDirect_SurfaceType, 26 kGpu_SurfaceType, 27 kGpuScratch_SurfaceType, 28 }; 29 release_storage(void * pixels,void * context)30 static void release_storage(void* pixels, void* context) { 31 SkASSERT(pixels == context); 32 sk_free(pixels); 33 } 34 createSurface(SurfaceType surfaceType,GrContext * context,SkImageInfo * requestedInfo=NULL)35 static SkSurface* createSurface(SurfaceType surfaceType, GrContext* context, 36 SkImageInfo* requestedInfo = NULL) { 37 static const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); 38 39 if (requestedInfo) { 40 *requestedInfo = info; 41 } 42 43 switch (surfaceType) { 44 case kRaster_SurfaceType: 45 return SkSurface::NewRaster(info); 46 case kRasterDirect_SurfaceType: { 47 const size_t rowBytes = info.minRowBytes(); 48 void* storage = sk_malloc_throw(info.getSafeSize(rowBytes)); 49 return SkSurface::NewRasterDirectReleaseProc(info, storage, rowBytes, 50 release_storage, storage); 51 } 52 case kGpu_SurfaceType: 53 return SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0, NULL); 54 case kGpuScratch_SurfaceType: 55 return SkSurface::NewRenderTarget(context, SkSurface::kYes_Budgeted, info, 0, NULL); 56 } 57 return NULL; 58 } 59 60 enum ImageType { 61 kRasterCopy_ImageType, 62 kRasterData_ImageType, 63 kGpu_ImageType, 64 kCodec_ImageType, 65 }; 66 67 #include "SkImageGenerator.h" 68 69 class EmptyGenerator : public SkImageGenerator { 70 public: EmptyGenerator()71 EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {} 72 }; 73 test_empty_image(skiatest::Reporter * reporter)74 static void test_empty_image(skiatest::Reporter* reporter) { 75 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); 76 77 REPORTER_ASSERT(reporter, NULL == SkImage::NewRasterCopy(info, NULL, 0)); 78 REPORTER_ASSERT(reporter, NULL == SkImage::NewRasterData(info, NULL, 0)); 79 REPORTER_ASSERT(reporter, NULL == SkImage::NewFromGenerator(SkNEW(EmptyGenerator))); 80 } 81 test_empty_surface(skiatest::Reporter * reporter,GrContext * ctx)82 static void test_empty_surface(skiatest::Reporter* reporter, GrContext* ctx) { 83 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType); 84 85 REPORTER_ASSERT(reporter, NULL == SkSurface::NewRaster(info)); 86 REPORTER_ASSERT(reporter, NULL == SkSurface::NewRasterDirect(info, NULL, 0)); 87 if (ctx) { 88 REPORTER_ASSERT(reporter, NULL == 89 SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info, 0, NULL)); 90 } 91 } 92 93 #if SK_SUPPORT_GPU test_wrapped_texture_surface(skiatest::Reporter * reporter,GrContext * ctx)94 static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext* ctx) { 95 if (NULL == ctx) { 96 return; 97 } 98 // Test the wrapped factory for SkSurface by creating a texture using ctx and then treat it as 99 // an external texture and wrap it in a SkSurface. 100 101 GrSurfaceDesc texDesc; 102 texDesc.fConfig = kRGBA_8888_GrPixelConfig; 103 texDesc.fFlags = kRenderTarget_GrSurfaceFlag; 104 texDesc.fWidth = texDesc.fHeight = 100; 105 texDesc.fSampleCnt = 0; 106 texDesc.fOrigin = kTopLeft_GrSurfaceOrigin; 107 SkAutoTUnref<GrSurface> dummySurface(ctx->textureProvider()->createTexture(texDesc, false)); 108 109 REPORTER_ASSERT(reporter, dummySurface && dummySurface->asTexture() && 110 dummySurface->asRenderTarget()); 111 if (!dummySurface || !dummySurface->asTexture() || !dummySurface->asRenderTarget()) { 112 return; 113 } 114 115 GrBackendObject textureHandle = dummySurface->asTexture()->getTextureHandle(); 116 117 GrBackendTextureDesc wrappedDesc; 118 wrappedDesc.fConfig = dummySurface->config(); 119 wrappedDesc.fWidth = dummySurface->width(); 120 wrappedDesc.fHeight = dummySurface->height(); 121 wrappedDesc.fOrigin = dummySurface->origin(); 122 wrappedDesc.fSampleCnt = dummySurface->asRenderTarget()->numSamples(); 123 wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag; 124 wrappedDesc.fTextureHandle = textureHandle; 125 126 SkAutoTUnref<SkSurface> surface(SkSurface::NewWrappedRenderTarget(ctx, wrappedDesc, NULL)); 127 REPORTER_ASSERT(reporter, surface); 128 } 129 #endif 130 131 test_image(skiatest::Reporter * reporter)132 static void test_image(skiatest::Reporter* reporter) { 133 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 134 size_t rowBytes = info.minRowBytes(); 135 size_t size = info.getSafeSize(rowBytes); 136 SkData* data = SkData::NewUninitialized(size); 137 138 REPORTER_ASSERT(reporter, data->unique()); 139 SkImage* image = SkImage::NewRasterData(info, data, rowBytes); 140 REPORTER_ASSERT(reporter, !data->unique()); 141 image->unref(); 142 REPORTER_ASSERT(reporter, data->unique()); 143 data->unref(); 144 } 145 createImage(ImageType imageType,GrContext * context,SkColor color)146 static SkImage* createImage(ImageType imageType, GrContext* context, SkColor color) { 147 const SkPMColor pmcolor = SkPreMultiplyColor(color); 148 const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); 149 const size_t rowBytes = info.minRowBytes(); 150 const size_t size = rowBytes * info.height(); 151 152 SkAutoTUnref<SkData> data(SkData::NewUninitialized(size)); 153 void* addr = data->writable_data(); 154 sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2)); 155 156 switch (imageType) { 157 case kRasterCopy_ImageType: 158 return SkImage::NewRasterCopy(info, addr, rowBytes); 159 case kRasterData_ImageType: 160 return SkImage::NewRasterData(info, data, rowBytes); 161 case kGpu_ImageType: { 162 SkAutoTUnref<SkSurface> surf( 163 SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0)); 164 surf->getCanvas()->clear(color); 165 return surf->newImageSnapshot(); 166 } 167 case kCodec_ImageType: { 168 SkBitmap bitmap; 169 bitmap.installPixels(info, addr, rowBytes); 170 SkAutoTUnref<SkData> src( 171 SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100)); 172 return SkImage::NewFromData(src); 173 } 174 } 175 SkASSERT(false); 176 return NULL; 177 } 178 set_pixels(SkPMColor pixels[],int count,SkPMColor color)179 static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) { 180 sk_memset32(pixels, color, count); 181 } has_pixels(const SkPMColor pixels[],int count,SkPMColor expected)182 static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) { 183 for (int i = 0; i < count; ++i) { 184 if (pixels[i] != expected) { 185 return false; 186 } 187 } 188 return true; 189 } 190 test_image_readpixels(skiatest::Reporter * reporter,SkImage * image,SkPMColor expected)191 static void test_image_readpixels(skiatest::Reporter* reporter, SkImage* image, 192 SkPMColor expected) { 193 const SkPMColor notExpected = ~expected; 194 195 const int w = 2, h = 2; 196 const size_t rowBytes = w * sizeof(SkPMColor); 197 SkPMColor pixels[w*h]; 198 199 SkImageInfo info; 200 201 info = SkImageInfo::MakeUnknown(w, h); 202 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0)); 203 204 // out-of-bounds should fail 205 info = SkImageInfo::MakeN32Premul(w, h); 206 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0)); 207 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h)); 208 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0)); 209 REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height())); 210 211 // top-left should succeed 212 set_pixels(pixels, w*h, notExpected); 213 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0)); 214 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); 215 216 // bottom-right should succeed 217 set_pixels(pixels, w*h, notExpected); 218 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 219 image->width() - w, image->height() - h)); 220 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected)); 221 222 // partial top-left should succeed 223 set_pixels(pixels, w*h, notExpected); 224 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1)); 225 REPORTER_ASSERT(reporter, pixels[3] == expected); 226 REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected)); 227 228 // partial bottom-right should succeed 229 set_pixels(pixels, w*h, notExpected); 230 REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 231 image->width() - 1, image->height() - 1)); 232 REPORTER_ASSERT(reporter, pixels[0] == expected); 233 REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected)); 234 } 235 test_imagepeek(skiatest::Reporter * reporter,GrContextFactory * factory)236 static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* factory) { 237 static const struct { 238 ImageType fType; 239 bool fPeekShouldSucceed; 240 const char* fName; 241 } gRec[] = { 242 { kRasterCopy_ImageType, true, "RasterCopy" }, 243 { kRasterData_ImageType, true, "RasterData" }, 244 { kGpu_ImageType, false, "Gpu" }, 245 { kCodec_ImageType, false, "Codec" }, 246 }; 247 248 const SkColor color = SK_ColorRED; 249 const SkPMColor pmcolor = SkPreMultiplyColor(color); 250 251 GrContext* ctx = NULL; 252 #if SK_SUPPORT_GPU 253 ctx = factory->get(GrContextFactory::kNative_GLContextType); 254 if (NULL == ctx) { 255 return; 256 } 257 #endif 258 259 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 260 SkImageInfo info; 261 size_t rowBytes; 262 263 SkAutoTUnref<SkImage> image(createImage(gRec[i].fType, ctx, color)); 264 if (!image.get()) { 265 SkDebugf("failed to createImage[%d] %s\n", i, gRec[i].fName); 266 continue; // gpu may not be enabled 267 } 268 const void* addr = image->peekPixels(&info, &rowBytes); 269 bool success = SkToBool(addr); 270 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success); 271 if (success) { 272 REPORTER_ASSERT(reporter, 10 == info.width()); 273 REPORTER_ASSERT(reporter, 10 == info.height()); 274 REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType()); 275 REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() || 276 kOpaque_SkAlphaType == info.alphaType()); 277 REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes); 278 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr); 279 } 280 281 test_image_readpixels(reporter, image, pmcolor); 282 } 283 } 284 test_canvaspeek(skiatest::Reporter * reporter,GrContextFactory * factory)285 static void test_canvaspeek(skiatest::Reporter* reporter, 286 GrContextFactory* factory) { 287 static const struct { 288 SurfaceType fType; 289 bool fPeekShouldSucceed; 290 } gRec[] = { 291 { kRaster_SurfaceType, true }, 292 { kRasterDirect_SurfaceType, true }, 293 #if SK_SUPPORT_GPU 294 { kGpu_SurfaceType, false }, 295 { kGpuScratch_SurfaceType, false }, 296 #endif 297 }; 298 299 const SkColor color = SK_ColorRED; 300 const SkPMColor pmcolor = SkPreMultiplyColor(color); 301 302 int cnt; 303 #if SK_SUPPORT_GPU 304 cnt = GrContextFactory::kGLContextTypeCnt; 305 #else 306 cnt = 1; 307 #endif 308 309 for (int i= 0; i < cnt; ++i) { 310 GrContext* context = NULL; 311 #if SK_SUPPORT_GPU 312 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i; 313 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) { 314 continue; 315 } 316 context = factory->get(glCtxType); 317 318 if (NULL == context) { 319 continue; 320 } 321 #endif 322 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 323 SkImageInfo info, requestInfo; 324 size_t rowBytes; 325 326 SkAutoTUnref<SkSurface> surface(createSurface(gRec[i].fType, context, 327 &requestInfo)); 328 surface->getCanvas()->clear(color); 329 330 const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes); 331 bool success = SkToBool(addr); 332 REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success); 333 334 SkImageInfo info2; 335 size_t rb2; 336 const void* addr2 = surface->peekPixels(&info2, &rb2); 337 338 if (success) { 339 REPORTER_ASSERT(reporter, requestInfo == info); 340 REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes); 341 REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr); 342 343 REPORTER_ASSERT(reporter, addr2 == addr); 344 REPORTER_ASSERT(reporter, info2 == info); 345 REPORTER_ASSERT(reporter, rb2 == rowBytes); 346 } else { 347 REPORTER_ASSERT(reporter, NULL == addr2); 348 } 349 } 350 } 351 } 352 TestSurfaceCopyOnWrite(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context)353 static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType, 354 GrContext* context) { 355 // Verify that the right canvas commands trigger a copy on write 356 SkSurface* surface = createSurface(surfaceType, context); 357 SkAutoTUnref<SkSurface> aur_surface(surface); 358 SkCanvas* canvas = surface->getCanvas(); 359 360 const SkRect testRect = 361 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 362 SkIntToScalar(4), SkIntToScalar(5)); 363 SkPath testPath; 364 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 365 SkIntToScalar(2), SkIntToScalar(1))); 366 367 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1); 368 369 SkRegion testRegion; 370 testRegion.setRect(testIRect); 371 372 373 const SkColor testColor = 0x01020304; 374 const SkPaint testPaint; 375 const SkPoint testPoints[3] = { 376 {SkIntToScalar(0), SkIntToScalar(0)}, 377 {SkIntToScalar(2), SkIntToScalar(1)}, 378 {SkIntToScalar(0), SkIntToScalar(2)} 379 }; 380 const size_t testPointCount = 3; 381 382 SkBitmap testBitmap; 383 testBitmap.allocN32Pixels(10, 10); 384 testBitmap.eraseColor(0); 385 386 SkRRect testRRect; 387 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1); 388 389 SkString testText("Hello World"); 390 const SkPoint testPoints2[] = { 391 { SkIntToScalar(0), SkIntToScalar(1) }, 392 { SkIntToScalar(1), SkIntToScalar(1) }, 393 { SkIntToScalar(2), SkIntToScalar(1) }, 394 { SkIntToScalar(3), SkIntToScalar(1) }, 395 { SkIntToScalar(4), SkIntToScalar(1) }, 396 { SkIntToScalar(5), SkIntToScalar(1) }, 397 { SkIntToScalar(6), SkIntToScalar(1) }, 398 { SkIntToScalar(7), SkIntToScalar(1) }, 399 { SkIntToScalar(8), SkIntToScalar(1) }, 400 { SkIntToScalar(9), SkIntToScalar(1) }, 401 { SkIntToScalar(10), SkIntToScalar(1) }, 402 }; 403 404 #define EXPECT_COPY_ON_WRITE(command) \ 405 { \ 406 SkImage* imageBefore = surface->newImageSnapshot(); \ 407 SkAutoTUnref<SkImage> aur_before(imageBefore); \ 408 canvas-> command ; \ 409 SkImage* imageAfter = surface->newImageSnapshot(); \ 410 SkAutoTUnref<SkImage> aur_after(imageAfter); \ 411 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \ 412 } 413 414 EXPECT_COPY_ON_WRITE(clear(testColor)) 415 EXPECT_COPY_ON_WRITE(drawPaint(testPaint)) 416 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \ 417 testPaint)) 418 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint)) 419 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint)) 420 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint)) 421 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint)) 422 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0)) 423 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect)) 424 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL)) 425 EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL)) 426 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint)) 427 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \ 428 testPaint)) 429 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \ 430 testPaint)) 431 } 432 TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context)433 static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter, 434 SurfaceType surfaceType, 435 GrContext* context) { 436 // This test succeeds by not triggering an assertion. 437 // The test verifies that the surface remains writable (usable) after 438 // acquiring and releasing a snapshot without triggering a copy on write. 439 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 440 SkCanvas* canvas = surface->getCanvas(); 441 canvas->clear(1); 442 surface->newImageSnapshot()->unref(); // Create and destroy SkImage 443 canvas->clear(2); // Must not assert internally 444 } 445 446 #if SK_SUPPORT_GPU Test_crbug263329(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context)447 static void Test_crbug263329(skiatest::Reporter* reporter, 448 SurfaceType surfaceType, 449 GrContext* context) { 450 // This is a regression test for crbug.com/263329 451 // Bug was caused by onCopyOnWrite releasing the old surface texture 452 // back to the scratch texture pool even though the texture is used 453 // by and active SkImage_Gpu. 454 SkAutoTUnref<SkSurface> surface1(createSurface(surfaceType, context)); 455 SkAutoTUnref<SkSurface> surface2(createSurface(surfaceType, context)); 456 SkCanvas* canvas1 = surface1->getCanvas(); 457 SkCanvas* canvas2 = surface2->getCanvas(); 458 canvas1->clear(1); 459 SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot()); 460 // Trigger copy on write, new backing is a scratch texture 461 canvas1->clear(2); 462 SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot()); 463 // Trigger copy on write, old backing should not be returned to scratch 464 // pool because it is held by image2 465 canvas1->clear(3); 466 467 canvas2->clear(4); 468 SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot()); 469 // Trigger copy on write on surface2. The new backing store should not 470 // be recycling a texture that is held by an existing image. 471 canvas2->clear(5); 472 SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot()); 473 REPORTER_ASSERT(reporter, image4->getTexture() != image3->getTexture()); 474 // The following assertion checks crbug.com/263329 475 REPORTER_ASSERT(reporter, image4->getTexture() != image2->getTexture()); 476 REPORTER_ASSERT(reporter, image4->getTexture() != image1->getTexture()); 477 REPORTER_ASSERT(reporter, image3->getTexture() != image2->getTexture()); 478 REPORTER_ASSERT(reporter, image3->getTexture() != image1->getTexture()); 479 REPORTER_ASSERT(reporter, image2->getTexture() != image1->getTexture()); 480 } 481 TestGetTexture(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context)482 static void TestGetTexture(skiatest::Reporter* reporter, 483 SurfaceType surfaceType, 484 GrContext* context) { 485 SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context)); 486 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 487 GrTexture* texture = image->getTexture(); 488 if (surfaceType == kGpu_SurfaceType || surfaceType == kGpuScratch_SurfaceType) { 489 REPORTER_ASSERT(reporter, texture); 490 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle()); 491 } else { 492 REPORTER_ASSERT(reporter, NULL == texture); 493 } 494 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); 495 REPORTER_ASSERT(reporter, image->getTexture() == texture); 496 } 497 498 #include "GrGpuResourcePriv.h" 499 #include "SkGpuDevice.h" 500 #include "SkImage_Gpu.h" 501 #include "SkSurface_Gpu.h" 502 is_budgeted(SkSurface * surf)503 SkSurface::Budgeted is_budgeted(SkSurface* surf) { 504 return ((SkSurface_Gpu*)surf)->getDevice()->accessRenderTarget()->resourcePriv().isBudgeted() ? 505 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted; 506 } 507 is_budgeted(SkImage * image)508 SkSurface::Budgeted is_budgeted(SkImage* image) { 509 return ((SkImage_Gpu*)image)->getTexture()->resourcePriv().isBudgeted() ? 510 SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted; 511 } 512 test_surface_budget(skiatest::Reporter * reporter,GrContext * context)513 static void test_surface_budget(skiatest::Reporter* reporter, GrContext* context) { 514 SkImageInfo info = SkImageInfo::MakeN32Premul(8,8); 515 for (int i = 0; i < 2; ++i) { 516 SkSurface::Budgeted sbudgeted = i ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted; 517 for (int j = 0; j < 2; ++j) { 518 SkSurface::Budgeted ibudgeted = j ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted; 519 SkAutoTUnref<SkSurface> 520 surface(SkSurface::NewRenderTarget(context, sbudgeted, info, 0)); 521 SkASSERT(surface); 522 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface)); 523 524 SkAutoTUnref<SkImage> image(surface->newImageSnapshot(ibudgeted)); 525 526 // Initially the image shares a texture with the surface, and the surface decides 527 // whether it is budgeted or not. 528 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface)); 529 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(image)); 530 531 // Now trigger copy-on-write 532 surface->getCanvas()->clear(SK_ColorBLUE); 533 534 // They don't share a texture anymore. They should each have made their own budget 535 // decision. 536 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface)); 537 REPORTER_ASSERT(reporter, ibudgeted == is_budgeted(image)); 538 } 539 } 540 } 541 542 #endif 543 TestSurfaceNoCanvas(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context,SkSurface::ContentChangeMode mode)544 static void TestSurfaceNoCanvas(skiatest::Reporter* reporter, 545 SurfaceType surfaceType, 546 GrContext* context, 547 SkSurface::ContentChangeMode mode) { 548 // Verifies the robustness of SkSurface for handling use cases where calls 549 // are made before a canvas is created. 550 { 551 // Test passes by not asserting 552 SkSurface* surface = createSurface(surfaceType, context); 553 SkAutoTUnref<SkSurface> aur_surface(surface); 554 surface->notifyContentWillChange(mode); 555 SkDEBUGCODE(surface->validate();) 556 } 557 { 558 SkSurface* surface = createSurface(surfaceType, context); 559 SkAutoTUnref<SkSurface> aur_surface(surface); 560 SkImage* image1 = surface->newImageSnapshot(); 561 SkAutoTUnref<SkImage> aur_image1(image1); 562 SkDEBUGCODE(image1->validate();) 563 SkDEBUGCODE(surface->validate();) 564 surface->notifyContentWillChange(mode); 565 SkDEBUGCODE(image1->validate();) 566 SkDEBUGCODE(surface->validate();) 567 SkImage* image2 = surface->newImageSnapshot(); 568 SkAutoTUnref<SkImage> aur_image2(image2); 569 SkDEBUGCODE(image2->validate();) 570 SkDEBUGCODE(surface->validate();) 571 REPORTER_ASSERT(reporter, image1 != image2); 572 } 573 574 } 575 DEF_GPUTEST(Surface,reporter,factory)576 DEF_GPUTEST(Surface, reporter, factory) { 577 test_image(reporter); 578 579 TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL); 580 TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL); 581 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode); 582 TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode); 583 584 test_empty_image(reporter); 585 test_empty_surface(reporter, NULL); 586 587 test_imagepeek(reporter, factory); 588 test_canvaspeek(reporter, factory); 589 590 #if SK_SUPPORT_GPU 591 TestGetTexture(reporter, kRaster_SurfaceType, NULL); 592 if (factory) { 593 for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) { 594 GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i; 595 if (!GrContextFactory::IsRenderingGLContext(glCtxType)) { 596 continue; 597 } 598 GrContext* context = factory->get(glCtxType); 599 if (context) { 600 Test_crbug263329(reporter, kGpu_SurfaceType, context); 601 Test_crbug263329(reporter, kGpuScratch_SurfaceType, context); 602 TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context); 603 TestSurfaceCopyOnWrite(reporter, kGpuScratch_SurfaceType, context); 604 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context); 605 TestSurfaceWritableAfterSnapshotRelease(reporter, kGpuScratch_SurfaceType, context); 606 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode); 607 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode); 608 TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode); 609 TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kRetain_ContentChangeMode); 610 TestGetTexture(reporter, kGpu_SurfaceType, context); 611 TestGetTexture(reporter, kGpuScratch_SurfaceType, context); 612 test_empty_surface(reporter, context); 613 test_surface_budget(reporter, context); 614 test_wrapped_texture_surface(reporter, context); 615 } 616 } 617 } 618 #endif 619 } 620 621 #if SK_SUPPORT_GPU make_desc_image(GrContext * ctx,int w,int h,GrBackendObject texID,bool doCopy)622 static SkImage* make_desc_image(GrContext* ctx, int w, int h, GrBackendObject texID, bool doCopy) { 623 GrBackendTextureDesc desc; 624 desc.fConfig = kSkia8888_GrPixelConfig; 625 // need to be a rendertarget for now... 626 desc.fFlags = kRenderTarget_GrBackendTextureFlag; 627 desc.fWidth = w; 628 desc.fHeight = h; 629 desc.fSampleCnt = 0; 630 desc.fTextureHandle = texID; 631 return doCopy ? SkImage::NewFromTextureCopy(ctx, desc) : SkImage::NewFromTexture(ctx, desc); 632 } 633 test_image_color(skiatest::Reporter * reporter,SkImage * image,SkPMColor expected)634 static void test_image_color(skiatest::Reporter* reporter, SkImage* image, SkPMColor expected) { 635 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); 636 SkPMColor pixel; 637 REPORTER_ASSERT(reporter, image->readPixels(info, &pixel, sizeof(pixel), 0, 0)); 638 REPORTER_ASSERT(reporter, pixel == expected); 639 } 640 DEF_GPUTEST(SkImage_NewFromTexture,reporter,factory)641 DEF_GPUTEST(SkImage_NewFromTexture, reporter, factory) { 642 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType); 643 if (!ctx) { 644 REPORTER_ASSERT(reporter, false); 645 return; 646 } 647 GrTextureProvider* provider = ctx->textureProvider(); 648 649 const int w = 10; 650 const int h = 10; 651 SkPMColor storage[w * h]; 652 const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED); 653 sk_memset32(storage, expected0, w * h); 654 655 GrSurfaceDesc desc; 656 desc.fFlags = kRenderTarget_GrSurfaceFlag; // needs to be a rendertarget for readpixels(); 657 desc.fOrigin = kDefault_GrSurfaceOrigin; 658 desc.fWidth = w; 659 desc.fHeight = h; 660 desc.fConfig = kSkia8888_GrPixelConfig; 661 desc.fSampleCnt = 0; 662 663 SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, false, storage, w * 4)); 664 if (!tex) { 665 REPORTER_ASSERT(reporter, false); 666 return; 667 } 668 669 GrBackendObject srcTex = tex->getTextureHandle(); 670 SkAutoTUnref<SkImage> refImg(make_desc_image(ctx, w, h, srcTex, false)); 671 SkAutoTUnref<SkImage> cpyImg(make_desc_image(ctx, w, h, srcTex, true)); 672 673 test_image_color(reporter, refImg, expected0); 674 test_image_color(reporter, cpyImg, expected0); 675 676 // Now lets jam new colors into our "external" texture, and see if the images notice 677 const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE); 678 sk_memset32(storage, expected1, w * h); 679 tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp); 680 681 // We expect the ref'd image to see the new color, but cpy'd one should still see the old color 682 test_image_color(reporter, refImg, expected1); 683 test_image_color(reporter, cpyImg, expected0); 684 } 685 #endif 686