ReadPixelsTest.cpp revision d6176b0dcacb124539e0cfd051e6d93a9782f020
1 2/* 3 * Copyright 2011 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 9#include "Test.h" 10#include "SkCanvas.h" 11#include "SkColorPriv.h" 12#include "SkDevice.h" 13#include "SkMathPriv.h" 14#include "SkRegion.h" 15#if SK_SUPPORT_GPU 16#include "SkGpuDevice.h" 17#endif 18 19 20static const int DEV_W = 100, DEV_H = 100; 21static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H); 22static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1, 23 DEV_H * SK_Scalar1); 24 25namespace { 26SkPMColor getCanvasColor(int x, int y) { 27 SkASSERT(x >= 0 && x < DEV_W); 28 SkASSERT(y >= 0 && y < DEV_H); 29 30 U8CPU r = x; 31 U8CPU g = y; 32 U8CPU b = 0xc; 33 34 U8CPU a = 0xff; 35 switch ((x+y) % 5) { 36 case 0: 37 a = 0xff; 38 break; 39 case 1: 40 a = 0x80; 41 break; 42 case 2: 43 a = 0xCC; 44 break; 45 case 4: 46 a = 0x01; 47 break; 48 case 3: 49 a = 0x00; 50 break; 51 } 52 return SkPremultiplyARGBInline(a, r, g, b); 53} 54 55SkPMColor getBitmapColor(int x, int y, int w, int h) { 56 int n = y * w + x; 57 58 U8CPU b = n & 0xff; 59 U8CPU g = (n >> 8) & 0xff; 60 U8CPU r = (n >> 16) & 0xff; 61 return SkPackARGB32(0xff, r, g , b); 62} 63 64SkPMColor convertConfig8888ToPMColor(SkCanvas::Config8888 config8888, 65 uint32_t color, 66 bool* premul) { 67 const uint8_t* c = reinterpret_cast<uint8_t*>(&color); 68 U8CPU a,r,g,b; 69 *premul = false; 70 switch (config8888) { 71 case SkCanvas::kNative_Premul_Config8888: 72 return color; 73 case SkCanvas::kNative_Unpremul_Config8888: 74 *premul = true; 75 a = SkGetPackedA32(color); 76 r = SkGetPackedR32(color); 77 g = SkGetPackedG32(color); 78 b = SkGetPackedB32(color); 79 break; 80 case SkCanvas::kBGRA_Unpremul_Config8888: 81 *premul = true; // fallthru 82 case SkCanvas::kBGRA_Premul_Config8888: 83 a = static_cast<U8CPU>(c[3]); 84 r = static_cast<U8CPU>(c[2]); 85 g = static_cast<U8CPU>(c[1]); 86 b = static_cast<U8CPU>(c[0]); 87 break; 88 case SkCanvas::kRGBA_Unpremul_Config8888: 89 *premul = true; // fallthru 90 case SkCanvas::kRGBA_Premul_Config8888: 91 a = static_cast<U8CPU>(c[3]); 92 r = static_cast<U8CPU>(c[0]); 93 g = static_cast<U8CPU>(c[1]); 94 b = static_cast<U8CPU>(c[2]); 95 break; 96 } 97 if (*premul) { 98 r = SkMulDiv255Ceiling(r, a); 99 g = SkMulDiv255Ceiling(g, a); 100 b = SkMulDiv255Ceiling(b, a); 101 } 102 return SkPackARGB32(a, r, g, b); 103} 104 105void fillCanvas(SkCanvas* canvas) { 106 static SkBitmap bmp; 107 if (bmp.isNull()) { 108 bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H); 109 bool alloc = bmp.allocPixels(); 110 SkASSERT(alloc); 111 SkAutoLockPixels alp(bmp); 112 intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels()); 113 for (int y = 0; y < DEV_H; ++y) { 114 for (int x = 0; x < DEV_W; ++x) { 115 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel()); 116 *pixel = getCanvasColor(x, y); 117 } 118 } 119 } 120 canvas->save(); 121 canvas->setMatrix(SkMatrix::I()); 122 canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op); 123 SkPaint paint; 124 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 125 canvas->drawBitmap(bmp, 0, 0, &paint); 126 canvas->restore(); 127} 128 129void fillBitmap(SkBitmap* bitmap) { 130 SkASSERT(bitmap->lockPixelsAreWritable()); 131 SkAutoLockPixels alp(*bitmap); 132 int w = bitmap->width(); 133 int h = bitmap->height(); 134 intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels()); 135 for (int y = 0; y < h; ++y) { 136 for (int x = 0; x < w; ++x) { 137 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel()); 138 *pixel = getBitmapColor(x, y, w, h); 139 } 140 } 141} 142 143bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) { 144 if (!didPremulConversion) { 145 return a == b; 146 } 147 int32_t aA = static_cast<int32_t>(SkGetPackedA32(a)); 148 int32_t aR = static_cast<int32_t>(SkGetPackedR32(a)); 149 int32_t aG = static_cast<int32_t>(SkGetPackedG32(a)); 150 int32_t aB = SkGetPackedB32(a); 151 152 int32_t bA = static_cast<int32_t>(SkGetPackedA32(b)); 153 int32_t bR = static_cast<int32_t>(SkGetPackedR32(b)); 154 int32_t bG = static_cast<int32_t>(SkGetPackedG32(b)); 155 int32_t bB = static_cast<int32_t>(SkGetPackedB32(b)); 156 157 return aA == bA && 158 SkAbs32(aR - bR) <= 1 && 159 SkAbs32(aG - bG) <= 1 && 160 SkAbs32(aB - bB) <= 1; 161} 162 163// checks the bitmap contains correct pixels after the readPixels 164// if the bitmap was prefilled with pixels it checks that these weren't 165// overwritten in the area outside the readPixels. 166bool checkRead(skiatest::Reporter* reporter, 167 const SkBitmap& bitmap, 168 int x, int y, 169 bool checkCanvasPixels, 170 bool checkBitmapPixels, 171 SkCanvas::Config8888 config8888) { 172 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); 173 SkASSERT(!bitmap.isNull()); 174 SkASSERT(checkCanvasPixels || checkBitmapPixels); 175 176 int bw = bitmap.width(); 177 int bh = bitmap.height(); 178 179 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh); 180 SkIRect clippedSrcRect = DEV_RECT; 181 if (!clippedSrcRect.intersect(srcRect)) { 182 clippedSrcRect.setEmpty(); 183 } 184 SkAutoLockPixels alp(bitmap); 185 intptr_t pixels = reinterpret_cast<intptr_t>(bitmap.getPixels()); 186 for (int by = 0; by < bh; ++by) { 187 for (int bx = 0; bx < bw; ++bx) { 188 int devx = bx + srcRect.fLeft; 189 int devy = by + srcRect.fTop; 190 191 uint32_t pixel = *reinterpret_cast<SkPMColor*>(pixels + by * bitmap.rowBytes() + bx * bitmap.bytesPerPixel()); 192 193 if (clippedSrcRect.contains(devx, devy)) { 194 if (checkCanvasPixels) { 195 SkPMColor canvasPixel = getCanvasColor(devx, devy); 196 bool didPremul; 197 SkPMColor pmPixel = convertConfig8888ToPMColor(config8888, pixel, &didPremul); 198 bool check; 199 REPORTER_ASSERT(reporter, check = checkPixel(pmPixel, canvasPixel, didPremul)); 200 if (!check) { 201 return false; 202 } 203 } 204 } else if (checkBitmapPixels) { 205 REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw, bh) == pixel); 206 if (getBitmapColor(bx, by, bw, bh) != pixel) { 207 return false; 208 } 209 } 210 } 211 } 212 return true; 213} 214 215enum BitmapInit { 216 kFirstBitmapInit = 0, 217 218 kNoPixels_BitmapInit = kFirstBitmapInit, 219 kTight_BitmapInit, 220 kRowBytes_BitmapInit, 221 222 kBitmapInitCnt 223}; 224 225BitmapInit nextBMI(BitmapInit bmi) { 226 int x = bmi; 227 return static_cast<BitmapInit>(++x); 228} 229 230 231void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init) { 232 int w = rect.width(); 233 int h = rect.height(); 234 int rowBytes = 0; 235 bool alloc = true; 236 switch (init) { 237 case kNoPixels_BitmapInit: 238 alloc = false; 239 case kTight_BitmapInit: 240 break; 241 case kRowBytes_BitmapInit: 242 rowBytes = w * sizeof(SkPMColor) + 16 * sizeof(SkPMColor); 243 break; 244 default: 245 SkASSERT(0); 246 break; 247 } 248 bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h, rowBytes); 249 if (alloc) { 250 bitmap->allocPixels(); 251 } 252} 253 254void ReadPixelsTest(skiatest::Reporter* reporter, GrContext* context) { 255 SkCanvas canvas; 256 257 const SkIRect testRects[] = { 258 // entire thing 259 DEV_RECT, 260 // larger on all sides 261 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10), 262 // fully contained 263 SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4), 264 // outside top left 265 SkIRect::MakeLTRB(-10, -10, -1, -1), 266 // touching top left corner 267 SkIRect::MakeLTRB(-10, -10, 0, 0), 268 // overlapping top left corner 269 SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4), 270 // overlapping top left and top right corners 271 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4), 272 // touching entire top edge 273 SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0), 274 // overlapping top right corner 275 SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4), 276 // contained in x, overlapping top edge 277 SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4), 278 // outside top right corner 279 SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1), 280 // touching top right corner 281 SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0), 282 // overlapping top left and bottom left corners 283 SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10), 284 // touching entire left edge 285 SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10), 286 // overlapping bottom left corner 287 SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10), 288 // contained in y, overlapping left edge 289 SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4), 290 // outside bottom left corner 291 SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10), 292 // touching bottom left corner 293 SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10), 294 // overlapping bottom left and bottom right corners 295 SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10), 296 // touching entire left edge 297 SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10), 298 // overlapping bottom right corner 299 SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10), 300 // overlapping top right and bottom right corners 301 SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10), 302 }; 303 304 for (int dtype = 0; dtype < 2; ++dtype) { 305 306 if (0 == dtype) { 307 canvas.setDevice(new SkDevice(SkBitmap::kARGB_8888_Config, 308 DEV_W, 309 DEV_H, 310 false))->unref(); 311 } else { 312// GPU device known not to work in the fixed pt build. 313#if defined(SK_SCALAR_IS_FIXED) || !SK_SUPPORT_GPU 314 continue; 315#else 316 canvas.setDevice(new SkGpuDevice(context, 317 SkBitmap::kARGB_8888_Config, 318 DEV_W, 319 DEV_H))->unref(); 320#endif 321 } 322 fillCanvas(&canvas); 323 324 static const SkCanvas::Config8888 gReadConfigs[] = { 325 SkCanvas::kNative_Premul_Config8888, 326 SkCanvas::kNative_Unpremul_Config8888, 327/** 328 * There is a bug in Ganesh (http://code.google.com/p/skia/issues/detail?id=438) 329 * that causes the readback of pixels from BGRA canvas to an RGBA bitmap to 330 * fail. This should be removed as soon as the issue above is resolved. 331 */ 332#if !defined(SK_BUILD_FOR_ANDROID) 333 SkCanvas::kBGRA_Premul_Config8888, 334 SkCanvas::kBGRA_Unpremul_Config8888, 335#endif 336 SkCanvas::kRGBA_Premul_Config8888, 337 SkCanvas::kRGBA_Unpremul_Config8888, 338 }; 339 for (size_t rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) { 340 const SkIRect& srcRect = testRects[rect]; 341 for (BitmapInit bmi = kFirstBitmapInit; 342 bmi < kBitmapInitCnt; 343 bmi = nextBMI(bmi)) { 344 for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) { 345 SkCanvas::Config8888 config8888 = gReadConfigs[c]; 346 SkBitmap bmp; 347 init_bitmap(&bmp, srcRect, bmi); 348 349 // if the bitmap has pixels allocated before the readPixels, 350 // note that and fill them with pattern 351 bool startsWithPixels = !bmp.isNull(); 352 if (startsWithPixels) { 353 fillBitmap(&bmp); 354 } 355 356 bool success = 357 canvas.readPixels(&bmp, srcRect.fLeft, 358 srcRect.fTop, config8888); 359 360 // we expect to succeed when the read isn't fully clipped 361 // out. 362 bool expectSuccess = SkIRect::Intersects(srcRect, DEV_RECT); 363 // determine whether we expected the read to succeed. 364 REPORTER_ASSERT(reporter, success == expectSuccess); 365 366 if (success || startsWithPixels) { 367 checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop, 368 success, startsWithPixels, config8888); 369 } else { 370 // if we had no pixels beforehand and the readPixels 371 // failed then our bitmap should still not have pixels 372 REPORTER_ASSERT(reporter, bmp.isNull()); 373 } 374 } 375 // check the old webkit version of readPixels that clips the 376 // bitmap size 377 SkBitmap wkbmp; 378 bool success = canvas.readPixels(srcRect, &wkbmp); 379 SkIRect clippedRect = DEV_RECT; 380 if (clippedRect.intersect(srcRect)) { 381 REPORTER_ASSERT(reporter, success); 382 checkRead(reporter, wkbmp, clippedRect.fLeft, 383 clippedRect.fTop, true, false, 384 SkCanvas::kNative_Premul_Config8888); 385 } else { 386 REPORTER_ASSERT(reporter, !success); 387 } 388 } 389 } 390 } 391} 392} 393 394#include "TestClassDef.h" 395DEFINE_GPUTESTCLASS("ReadPixels", ReadPixelsTestClass, ReadPixelsTest) 396 397