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 |