| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkCanvas.h" | 8 #include "SkCanvas.h" |
| 9 #include "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
| 10 #include "SkMathPriv.h" | 10 #include "SkMathPriv.h" |
| 11 #include "SkRegion.h" | 11 #include "SkRegion.h" |
| 12 #include "SkSurface.h" | 12 #include "SkSurface.h" |
| 13 #include "Test.h" | 13 #include "Test.h" |
| 14 #include "sk_tool_utils.h" | 14 #include "sk_tool_utils.h" |
| 15 | 15 |
| 16 #if SK_SUPPORT_GPU | 16 #if SK_SUPPORT_GPU |
| 17 #include "GrContextFactory.h" | 17 #include "GrContext.h" |
| 18 #include "SkGpuDevice.h" | |
| 19 #else | |
| 20 class GrContext; | |
| 21 class GrContextFactory; | |
| 22 #endif | 18 #endif |
| 23 | 19 |
| 20 #include <initializer_list> |
| 21 |
| 24 static const int DEV_W = 100, DEV_H = 100; | 22 static const int DEV_W = 100, DEV_H = 100; |
| 25 static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H); | 23 static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H); |
| 26 static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1, | 24 static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1, |
| 27 DEV_H * SK_Scalar1); | 25 DEV_H * SK_Scalar1); |
| 28 static const U8CPU DEV_PAD = 0xee; | 26 static const U8CPU DEV_PAD = 0xee; |
| 29 | 27 |
| 30 static SkPMColor get_canvas_color(int x, int y) { | 28 static SkPMColor get_canvas_color(int x, int y) { |
| 31 SkASSERT(x >= 0 && x < DEV_W); | 29 SkASSERT(x >= 0 && x < DEV_W); |
| 32 SkASSERT(y >= 0 && y < DEV_H); | 30 SkASSERT(y >= 0 && y < DEV_H); |
| 33 | 31 |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 return false; | 245 return false; |
| 248 } | 246 } |
| 249 } | 247 } |
| 250 } | 248 } |
| 251 canvasPixels += canvasRowBytes/4; | 249 canvasPixels += canvasRowBytes/4; |
| 252 } | 250 } |
| 253 | 251 |
| 254 return true; | 252 return true; |
| 255 } | 253 } |
| 256 | 254 |
| 257 enum DevType { | |
| 258 kRaster_DevType, | |
| 259 #if SK_SUPPORT_GPU | |
| 260 kGpu_BottomLeft_DevType, | |
| 261 kGpu_TopLeft_DevType, | |
| 262 #endif | |
| 263 }; | |
| 264 | |
| 265 struct CanvasConfig { | |
| 266 DevType fDevType; | |
| 267 bool fTightRowBytes; | |
| 268 }; | |
| 269 | |
| 270 static const CanvasConfig gCanvasConfigs[] = { | |
| 271 {kRaster_DevType, true}, | |
| 272 {kRaster_DevType, false}, | |
| 273 #if SK_SUPPORT_GPU | |
| 274 {kGpu_BottomLeft_DevType, true}, // row bytes has no meaning on gpu devices | |
| 275 {kGpu_TopLeft_DevType, true}, // row bytes has no meaning on gpu devices | |
| 276 #endif | |
| 277 }; | |
| 278 | |
| 279 #include "SkMallocPixelRef.h" | 255 #include "SkMallocPixelRef.h" |
| 280 | 256 |
| 281 // This is a tricky pattern, because we have to setConfig+rowBytes AND specify | 257 // This is a tricky pattern, because we have to setConfig+rowBytes AND specify |
| 282 // a custom pixelRef (which also has to specify its rowBytes), so we have to be | 258 // a custom pixelRef (which also has to specify its rowBytes), so we have to be |
| 283 // sure that the two rowBytes match (and the infos match). | 259 // sure that the two rowBytes match (and the infos match). |
| 284 // | 260 // |
| 285 static bool alloc_row_bytes(SkBitmap* bm, const SkImageInfo& info, size_t rowByt
es) { | 261 static bool alloc_row_bytes(SkBitmap* bm, const SkImageInfo& info, size_t rowByt
es) { |
| 286 if (!bm->setInfo(info, rowBytes)) { | 262 if (!bm->setInfo(info, rowBytes)) { |
| 287 return false; | 263 return false; |
| 288 } | 264 } |
| 289 SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, rowBytes, nullptr); | 265 SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, rowBytes, nullptr); |
| 290 bm->setPixelRef(pr)->unref(); | 266 bm->setPixelRef(pr)->unref(); |
| 291 return true; | 267 return true; |
| 292 } | 268 } |
| 293 | 269 |
| 294 static void free_pixels(void* pixels, void* ctx) { | 270 static void free_pixels(void* pixels, void* ctx) { |
| 295 sk_free(pixels); | 271 sk_free(pixels); |
| 296 } | 272 } |
| 297 | 273 |
| 298 static SkSurface* create_surface(const CanvasConfig& c, GrContext* grCtx) { | |
| 299 SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H); | |
| 300 switch (c.fDevType) { | |
| 301 case kRaster_DevType: { | |
| 302 const size_t rowBytes = c.fTightRowBytes ? info.minRowBytes() : 4 *
DEV_W + 100; | |
| 303 const size_t size = info.getSafeSize(rowBytes); | |
| 304 void* pixels = sk_malloc_throw(size); | |
| 305 // if rowBytes isn't tight then set the padding to a known value | |
| 306 if (!c.fTightRowBytes) { | |
| 307 memset(pixels, DEV_PAD, size); | |
| 308 } | |
| 309 return SkSurface::NewRasterDirectReleaseProc(info, pixels, rowBytes,
free_pixels, nullptr); | |
| 310 } | |
| 311 #if SK_SUPPORT_GPU | |
| 312 case kGpu_BottomLeft_DevType: | |
| 313 case kGpu_TopLeft_DevType: | |
| 314 GrSurfaceDesc desc; | |
| 315 desc.fFlags = kRenderTarget_GrSurfaceFlag; | |
| 316 desc.fWidth = DEV_W; | |
| 317 desc.fHeight = DEV_H; | |
| 318 desc.fConfig = kSkia8888_GrPixelConfig; | |
| 319 desc.fOrigin = kGpu_TopLeft_DevType == c.fDevType ? | |
| 320 kTopLeft_GrSurfaceOrigin : kBottomLeft_GrSurfaceOrigin; | |
| 321 SkAutoTUnref<GrTexture> texture(grCtx->textureProvider()->createText
ure(desc, false)); | |
| 322 return SkSurface::NewRenderTargetDirect(texture->asRenderTarget()); | |
| 323 #endif | |
| 324 } | |
| 325 return nullptr; | |
| 326 } | |
| 327 | |
| 328 static bool setup_bitmap(SkBitmap* bm, SkColorType ct, SkAlphaType at, int w, in
t h, int tightRB) { | 274 static bool setup_bitmap(SkBitmap* bm, SkColorType ct, SkAlphaType at, int w, in
t h, int tightRB) { |
| 329 size_t rowBytes = tightRB ? 0 : 4 * w + 60; | 275 size_t rowBytes = tightRB ? 0 : 4 * w + 60; |
| 330 SkImageInfo info = SkImageInfo::Make(w, h, ct, at); | 276 SkImageInfo info = SkImageInfo::Make(w, h, ct, at); |
| 331 if (!alloc_row_bytes(bm, info, rowBytes)) { | 277 if (!alloc_row_bytes(bm, info, rowBytes)) { |
| 332 return false; | 278 return false; |
| 333 } | 279 } |
| 334 SkAutoLockPixels alp(*bm); | 280 SkAutoLockPixels alp(*bm); |
| 335 for (int y = 0; y < h; ++y) { | 281 for (int y = 0; y < h; ++y) { |
| 336 for (int x = 0; x < w; ++x) { | 282 for (int x = 0; x < w; ++x) { |
| 337 *bm->getAddr32(x, y) = get_bitmap_color(x, y, w, ct, at); | 283 *bm->getAddr32(x, y) = get_bitmap_color(x, y, w, ct, at); |
| 338 } | 284 } |
| 339 } | 285 } |
| 340 return true; | 286 return true; |
| 341 } | 287 } |
| 342 | 288 |
| 343 static void call_writepixels(SkCanvas* canvas) { | 289 static void call_writepixels(SkCanvas* canvas) { |
| 344 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); | 290 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); |
| 345 SkPMColor pixel = 0; | 291 SkPMColor pixel = 0; |
| 346 canvas->writePixels(info, &pixel, sizeof(SkPMColor), 0, 0); | 292 canvas->writePixels(info, &pixel, sizeof(SkPMColor), 0, 0); |
| 347 } | 293 } |
| 348 | 294 |
| 349 static void test_surface_genid(skiatest::Reporter* reporter) { | 295 DEF_TEST(WritePixelsSurfaceGenID, reporter) { |
| 350 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); | 296 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); |
| 351 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info)); | 297 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info)); |
| 352 uint32_t genID1 = surface->generationID(); | 298 uint32_t genID1 = surface->generationID(); |
| 353 call_writepixels(surface->getCanvas()); | 299 call_writepixels(surface->getCanvas()); |
| 354 uint32_t genID2 = surface->generationID(); | 300 uint32_t genID2 = surface->generationID(); |
| 355 REPORTER_ASSERT(reporter, genID1 != genID2); | 301 REPORTER_ASSERT(reporter, genID1 != genID2); |
| 356 } | 302 } |
| 357 | 303 |
| 358 DEF_GPUTEST(WritePixels, reporter, factory) { | 304 static void test_write_pixels(skiatest::Reporter* reporter, SkSurface* surface)
{ |
| 359 test_surface_genid(reporter); | |
| 360 | |
| 361 SkCanvas canvas; | |
| 362 | |
| 363 const SkIRect testRects[] = { | 305 const SkIRect testRects[] = { |
| 364 // entire thing | 306 // entire thing |
| 365 DEV_RECT, | 307 DEV_RECT, |
| 366 // larger on all sides | 308 // larger on all sides |
| 367 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10), | 309 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10), |
| 368 // fully contained | 310 // fully contained |
| 369 SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4), | 311 SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4), |
| 370 // outside top left | 312 // outside top left |
| 371 SkIRect::MakeLTRB(-10, -10, -1, -1), | 313 SkIRect::MakeLTRB(-10, -10, -1, -1), |
| 372 // touching top left corner | 314 // touching top left corner |
| (...skipping 27 matching lines...) Expand all Loading... |
| 400 // overlapping bottom left and bottom right corners | 342 // overlapping bottom left and bottom right corners |
| 401 SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10), | 343 SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10), |
| 402 // touching entire left edge | 344 // touching entire left edge |
| 403 SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10), | 345 SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10), |
| 404 // overlapping bottom right corner | 346 // overlapping bottom right corner |
| 405 SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10), | 347 SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10), |
| 406 // overlapping top right and bottom right corners | 348 // overlapping top right and bottom right corners |
| 407 SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10), | 349 SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10), |
| 408 }; | 350 }; |
| 409 | 351 |
| 410 for (size_t i = 0; i < SK_ARRAY_COUNT(gCanvasConfigs); ++i) { | 352 SkCanvas& canvas = *surface->getCanvas(); |
| 411 int glCtxTypeCnt = 1; | |
| 412 #if SK_SUPPORT_GPU | |
| 413 bool isGPUDevice = kGpu_TopLeft_DevType == gCanvasConfigs[i].fDevType || | |
| 414 kGpu_BottomLeft_DevType == gCanvasConfigs[i].fDevType
; | |
| 415 if (isGPUDevice) { | |
| 416 glCtxTypeCnt = GrContextFactory::kGLContextTypeCnt; | |
| 417 } | |
| 418 #endif | |
| 419 for (int glCtxType = 0; glCtxType < glCtxTypeCnt; ++glCtxType) { | |
| 420 GrContext* context = nullptr; | |
| 421 #if SK_SUPPORT_GPU | |
| 422 if (isGPUDevice) { | |
| 423 GrContextFactory::GLContextType type = | |
| 424 static_cast<GrContextFactory::GLContextType>(glCtxType); | |
| 425 if (!GrContextFactory::IsRenderingGLContext(type)) { | |
| 426 continue; | |
| 427 } | |
| 428 context = factory->get(type); | |
| 429 if (nullptr == context) { | |
| 430 continue; | |
| 431 } | |
| 432 } | |
| 433 #endif | |
| 434 | 353 |
| 435 SkAutoTUnref<SkSurface> surface(create_surface(gCanvasConfigs[i], co
ntext)); | 354 static const struct { |
| 436 SkCanvas& canvas = *surface->getCanvas(); | 355 SkColorType fColorType; |
| 356 SkAlphaType fAlphaType; |
| 357 } gSrcConfigs[] = { |
| 358 { kRGBA_8888_SkColorType, kPremul_SkAlphaType }, |
| 359 { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType }, |
| 360 { kBGRA_8888_SkColorType, kPremul_SkAlphaType }, |
| 361 { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType }, |
| 362 }; |
| 363 for (size_t r = 0; r < SK_ARRAY_COUNT(testRects); ++r) { |
| 364 const SkIRect& rect = testRects[r]; |
| 365 for (int tightBmp = 0; tightBmp < 2; ++tightBmp) { |
| 366 for (size_t c = 0; c < SK_ARRAY_COUNT(gSrcConfigs); ++c) { |
| 367 const SkColorType ct = gSrcConfigs[c].fColorType; |
| 368 const SkAlphaType at = gSrcConfigs[c].fAlphaType; |
| 437 | 369 |
| 438 static const struct { | 370 fill_canvas(&canvas); |
| 439 SkColorType fColorType; | 371 SkBitmap bmp; |
| 440 SkAlphaType fAlphaType; | 372 REPORTER_ASSERT(reporter, setup_bitmap(&bmp, ct, at, rect.width(
), |
| 441 } gSrcConfigs[] = { | 373 rect.height(), SkToBool(t
ightBmp))); |
| 442 { kRGBA_8888_SkColorType, kPremul_SkAlphaType }, | 374 uint32_t idBefore = surface->generationID(); |
| 443 { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType }, | |
| 444 { kBGRA_8888_SkColorType, kPremul_SkAlphaType }, | |
| 445 { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType }, | |
| 446 }; | |
| 447 for (size_t r = 0; r < SK_ARRAY_COUNT(testRects); ++r) { | |
| 448 const SkIRect& rect = testRects[r]; | |
| 449 for (int tightBmp = 0; tightBmp < 2; ++tightBmp) { | |
| 450 for (size_t c = 0; c < SK_ARRAY_COUNT(gSrcConfigs); ++c) { | |
| 451 const SkColorType ct = gSrcConfigs[c].fColorType; | |
| 452 const SkAlphaType at = gSrcConfigs[c].fAlphaType; | |
| 453 | 375 |
| 454 fill_canvas(&canvas); | 376 // sk_tool_utils::write_pixels(&canvas, bmp, rect.fLeft, rect.fT
op, ct, at); |
| 455 SkBitmap bmp; | 377 canvas.writePixels(bmp, rect.fLeft, rect.fTop); |
| 456 REPORTER_ASSERT(reporter, setup_bitmap(&bmp, ct, at, rec
t.width(), | |
| 457 rect.height(), Sk
ToBool(tightBmp))); | |
| 458 uint32_t idBefore = surface->generationID(); | |
| 459 | 378 |
| 460 // sk_tool_utils::write_pixels(&canvas, bmp, rect.fLeft,
rect.fTop, ct, at); | 379 uint32_t idAfter = surface->generationID(); |
| 461 canvas.writePixels(bmp, rect.fLeft, rect.fTop); | 380 REPORTER_ASSERT(reporter, check_write(reporter, &canvas, bmp, |
| 381 rect.fLeft, rect.fTop)); |
| 462 | 382 |
| 463 uint32_t idAfter = surface->generationID(); | 383 // we should change the genID iff pixels were actually written. |
| 464 REPORTER_ASSERT(reporter, check_write(reporter, &canvas,
bmp, | 384 SkIRect canvasRect = SkIRect::MakeSize(canvas.getDeviceSize()); |
| 465 rect.fLeft, rect.f
Top)); | 385 SkIRect writeRect = SkIRect::MakeXYWH(rect.fLeft, rect.fTop, |
| 466 | 386 bmp.width(), bmp.height())
; |
| 467 // we should change the genID iff pixels were actually w
ritten. | 387 bool intersects = SkIRect::Intersects(canvasRect, writeRect) ; |
| 468 SkIRect canvasRect = SkIRect::MakeSize(canvas.getDeviceS
ize()); | 388 REPORTER_ASSERT(reporter, intersects == (idBefore != idAfter)); |
| 469 SkIRect writeRect = SkIRect::MakeXYWH(rect.fLeft, rect.f
Top, | |
| 470 bmp.width(), bmp.h
eight()); | |
| 471 bool intersects = SkIRect::Intersects(canvasRect, writeR
ect) ; | |
| 472 REPORTER_ASSERT(reporter, intersects == (idBefore != idA
fter)); | |
| 473 } | |
| 474 } | |
| 475 } | 389 } |
| 476 } | 390 } |
| 477 } | 391 } |
| 478 } | 392 } |
| 393 DEF_TEST(WritePixels, reporter) { |
| 394 const SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H); |
| 395 for (auto& tightRowBytes : { true, false }) { |
| 396 const size_t rowBytes = tightRowBytes ? info.minRowBytes() : 4 * DEV_W +
100; |
| 397 const size_t size = info.getSafeSize(rowBytes); |
| 398 void* pixels = sk_malloc_throw(size); |
| 399 // if rowBytes isn't tight then set the padding to a known value |
| 400 if (!tightRowBytes) { |
| 401 memset(pixels, DEV_PAD, size); |
| 402 } |
| 403 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterDirectReleaseProc(in
fo, pixels, rowBytes, free_pixels, nullptr)); |
| 404 test_write_pixels(reporter, surface); |
| 405 } |
| 406 } |
| 407 #if SK_SUPPORT_GPU |
| 408 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixels_Gpu, reporter, context) { |
| 409 for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin
}) { |
| 410 GrSurfaceDesc desc; |
| 411 desc.fFlags = kRenderTarget_GrSurfaceFlag; |
| 412 desc.fWidth = DEV_W; |
| 413 desc.fHeight = DEV_H; |
| 414 desc.fConfig = kSkia8888_GrPixelConfig; |
| 415 desc.fOrigin = origin; |
| 416 SkAutoTUnref<GrTexture> texture(context->textureProvider()->createTextur
e(desc, false)); |
| 417 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect(texture
->asRenderTarget())); |
| 418 test_write_pixels(reporter, surface); |
| 419 } |
| 420 } |
| 421 #endif |
| OLD | NEW |