WritePixelsTest.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /*
  2. * Copyright 2011 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. #include "include/core/SkCanvas.h"
  8. #include "include/core/SkSurface.h"
  9. #include "include/private/SkColorData.h"
  10. #include "include/private/SkImageInfoPriv.h"
  11. #include "src/core/SkMathPriv.h"
  12. #include "tests/Test.h"
  13. #include "tools/ToolUtils.h"
  14. #include "include/gpu/GrBackendSurface.h"
  15. #include "include/gpu/GrContext.h"
  16. #include "src/gpu/GrContextPriv.h"
  17. #include "src/gpu/GrGpu.h"
  18. #include "src/gpu/GrProxyProvider.h"
  19. #include <initializer_list>
  20. static const int DEV_W = 100, DEV_H = 100;
  21. static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
  22. static const U8CPU DEV_PAD = 0xee;
  23. static SkPMColor get_canvas_color(int x, int y) {
  24. SkASSERT(x >= 0 && x < DEV_W);
  25. SkASSERT(y >= 0 && y < DEV_H);
  26. U8CPU r = x;
  27. U8CPU g = y;
  28. U8CPU b = 0xc;
  29. U8CPU a = 0x0;
  30. switch ((x+y) % 5) {
  31. case 0:
  32. a = 0xff;
  33. break;
  34. case 1:
  35. a = 0x80;
  36. break;
  37. case 2:
  38. a = 0xCC;
  39. break;
  40. case 3:
  41. a = 0x00;
  42. break;
  43. case 4:
  44. a = 0x01;
  45. break;
  46. }
  47. return SkPremultiplyARGBInline(a, r, g, b);
  48. }
  49. // assumes any premu/.unpremul has been applied
  50. static uint32_t pack_color_type(SkColorType ct, U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
  51. uint32_t r32;
  52. uint8_t* result = reinterpret_cast<uint8_t*>(&r32);
  53. switch (ct) {
  54. case kBGRA_8888_SkColorType:
  55. result[0] = b;
  56. result[1] = g;
  57. result[2] = r;
  58. result[3] = a;
  59. break;
  60. case kRGBA_8888_SkColorType: // fallthrough
  61. case kRGB_888x_SkColorType:
  62. result[0] = r;
  63. result[1] = g;
  64. result[2] = b;
  65. result[3] = a;
  66. break;
  67. default:
  68. SkASSERT(0);
  69. return 0;
  70. }
  71. return r32;
  72. }
  73. static uint32_t get_bitmap_color(int x, int y, int w, SkColorType ct, SkAlphaType at) {
  74. int n = y * w + x;
  75. U8CPU b = n & 0xff;
  76. U8CPU g = (n >> 8) & 0xff;
  77. U8CPU r = (n >> 16) & 0xff;
  78. U8CPU a = 0;
  79. switch ((x+y) % 5) {
  80. case 4:
  81. a = 0xff;
  82. break;
  83. case 3:
  84. a = 0x80;
  85. break;
  86. case 2:
  87. a = 0xCC;
  88. break;
  89. case 1:
  90. a = 0x01;
  91. break;
  92. case 0:
  93. a = 0x00;
  94. break;
  95. }
  96. if (kPremul_SkAlphaType == at) {
  97. r = SkMulDiv255Ceiling(r, a);
  98. g = SkMulDiv255Ceiling(g, a);
  99. b = SkMulDiv255Ceiling(b, a);
  100. }
  101. return pack_color_type(ct, a, r, g , b);
  102. }
  103. static void fill_surface(SkSurface* surface) {
  104. SkBitmap bmp;
  105. bmp.allocN32Pixels(DEV_W, DEV_H);
  106. for (int y = 0; y < DEV_H; ++y) {
  107. for (int x = 0; x < DEV_W; ++x) {
  108. *bmp.getAddr32(x, y) = get_canvas_color(x, y);
  109. }
  110. }
  111. surface->writePixels(bmp, 0, 0);
  112. }
  113. /**
  114. * Lucky for us, alpha is always in the same spot (SK_A32_SHIFT), for both RGBA and BGRA.
  115. * Thus this routine doesn't need to know the exact colortype
  116. */
  117. static uint32_t premul(uint32_t color) {
  118. unsigned a = SkGetPackedA32(color);
  119. // these next three are not necessarily r,g,b in that order, but they are r,g,b in some order.
  120. unsigned c0 = SkGetPackedR32(color);
  121. unsigned c1 = SkGetPackedG32(color);
  122. unsigned c2 = SkGetPackedB32(color);
  123. c0 = SkMulDiv255Ceiling(c0, a);
  124. c1 = SkMulDiv255Ceiling(c1, a);
  125. c2 = SkMulDiv255Ceiling(c2, a);
  126. return SkPackARGB32NoCheck(a, c0, c1, c2);
  127. }
  128. static SkPMColor convert_to_PMColor(SkColorType ct, SkAlphaType at, uint32_t color) {
  129. if (kUnpremul_SkAlphaType == at) {
  130. color = premul(color);
  131. }
  132. switch (ct) {
  133. case kRGBA_8888_SkColorType:
  134. case kRGB_888x_SkColorType: // fallthrough
  135. color = SkSwizzle_RGBA_to_PMColor(color);
  136. break;
  137. case kBGRA_8888_SkColorType:
  138. color = SkSwizzle_BGRA_to_PMColor(color);
  139. break;
  140. default:
  141. SkASSERT(0);
  142. break;
  143. }
  144. return color;
  145. }
  146. static bool check_pixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
  147. if (!didPremulConversion) {
  148. return a == b;
  149. }
  150. int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
  151. int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
  152. int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
  153. int32_t aB = SkGetPackedB32(a);
  154. int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
  155. int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
  156. int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
  157. int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
  158. return aA == bA &&
  159. SkAbs32(aR - bR) <= 1 &&
  160. SkAbs32(aG - bG) <= 1 &&
  161. SkAbs32(aB - bB) <= 1;
  162. }
  163. bool write_should_succeed(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, bool isGPU) {
  164. if (!SkImageInfoValidConversion(dstInfo, srcInfo)) {
  165. return false;
  166. }
  167. if (!isGPU) {
  168. return true;
  169. }
  170. // The GPU backend supports writing unpremul data to a premul dst but not vice versa.
  171. if (srcInfo.alphaType() == kPremul_SkAlphaType &&
  172. dstInfo.alphaType() == kUnpremul_SkAlphaType) {
  173. return false;
  174. }
  175. if (!SkColorTypeIsAlwaysOpaque(srcInfo.colorType()) &&
  176. SkColorTypeIsAlwaysOpaque(dstInfo.colorType())) {
  177. return false;
  178. }
  179. // The source has no alpha value and the dst is only alpha
  180. if (SkColorTypeIsAlwaysOpaque(srcInfo.colorType()) &&
  181. SkColorTypeIsAlphaOnly(dstInfo.colorType())) {
  182. return false;
  183. }
  184. return true;
  185. }
  186. static bool check_write(skiatest::Reporter* reporter, SkSurface* surf, SkAlphaType surfaceAlphaType,
  187. const SkBitmap& bitmap, int writeX, int writeY) {
  188. size_t canvasRowBytes;
  189. const uint32_t* canvasPixels;
  190. // Can't use canvas->peekPixels(), as we are trying to look at GPU pixels sometimes as well.
  191. // At some point this will be unsupported, as we won't allow accessBitmap() to magically call
  192. // readPixels for the client.
  193. SkBitmap secretDevBitmap;
  194. secretDevBitmap.allocN32Pixels(surf->width(), surf->height());
  195. if (!surf->readPixels(secretDevBitmap, 0, 0)) {
  196. return false;
  197. }
  198. canvasRowBytes = secretDevBitmap.rowBytes();
  199. canvasPixels = static_cast<const uint32_t*>(secretDevBitmap.getPixels());
  200. if (nullptr == canvasPixels) {
  201. return false;
  202. }
  203. if (surf->width() != DEV_W || surf->height() != DEV_H) {
  204. return false;
  205. }
  206. const SkImageInfo bmInfo = bitmap.info();
  207. SkIRect writeRect = SkIRect::MakeXYWH(writeX, writeY, bitmap.width(), bitmap.height());
  208. for (int cy = 0; cy < DEV_H; ++cy) {
  209. for (int cx = 0; cx < DEV_W; ++cx) {
  210. SkPMColor canvasPixel = canvasPixels[cx];
  211. if (writeRect.contains(cx, cy)) {
  212. int bx = cx - writeX;
  213. int by = cy - writeY;
  214. uint32_t bmpColor8888 = get_bitmap_color(bx, by, bitmap.width(),
  215. bmInfo.colorType(), bmInfo.alphaType());
  216. bool mul = (kUnpremul_SkAlphaType == bmInfo.alphaType());
  217. SkPMColor bmpPMColor = convert_to_PMColor(bmInfo.colorType(), bmInfo.alphaType(),
  218. bmpColor8888);
  219. if (bmInfo.alphaType() == kOpaque_SkAlphaType ||
  220. surfaceAlphaType == kOpaque_SkAlphaType) {
  221. bmpPMColor |= 0xFF000000;
  222. }
  223. if (!check_pixel(bmpPMColor, canvasPixel, mul)) {
  224. ERRORF(reporter, "Expected canvas pixel at %d, %d to be 0x%08x, got 0x%08x. "
  225. "Write performed premul: %d", cx, cy, bmpPMColor, canvasPixel, mul);
  226. return false;
  227. }
  228. } else {
  229. SkPMColor testColor = get_canvas_color(cx, cy);
  230. if (canvasPixel != testColor) {
  231. ERRORF(reporter, "Canvas pixel outside write rect at %d, %d changed."
  232. " Should be 0x%08x, got 0x%08x. ", cx, cy, testColor, canvasPixel);
  233. return false;
  234. }
  235. }
  236. }
  237. if (cy != DEV_H -1) {
  238. const char* pad = reinterpret_cast<const char*>(canvasPixels + DEV_W);
  239. for (size_t px = 0; px < canvasRowBytes - 4 * DEV_W; ++px) {
  240. bool check;
  241. REPORTER_ASSERT(reporter, check = (pad[px] == static_cast<char>(DEV_PAD)));
  242. if (!check) {
  243. return false;
  244. }
  245. }
  246. }
  247. canvasPixels += canvasRowBytes/4;
  248. }
  249. return true;
  250. }
  251. #include "include/core/SkMallocPixelRef.h"
  252. // This is a tricky pattern, because we have to setConfig+rowBytes AND specify
  253. // a custom pixelRef (which also has to specify its rowBytes), so we have to be
  254. // sure that the two rowBytes match (and the infos match).
  255. //
  256. static bool alloc_row_bytes(SkBitmap* bm, const SkImageInfo& info, size_t rowBytes) {
  257. if (!bm->setInfo(info, rowBytes)) {
  258. return false;
  259. }
  260. sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, rowBytes);
  261. bm->setPixelRef(std::move(pr), 0, 0);
  262. return true;
  263. }
  264. static void free_pixels(void* pixels, void* ctx) {
  265. sk_free(pixels);
  266. }
  267. static bool setup_bitmap(SkBitmap* bm, SkColorType ct, SkAlphaType at, int w, int h, int tightRB) {
  268. size_t rowBytes = tightRB ? 0 : 4 * w + 60;
  269. SkImageInfo info = SkImageInfo::Make(w, h, ct, at);
  270. if (!alloc_row_bytes(bm, info, rowBytes)) {
  271. return false;
  272. }
  273. for (int y = 0; y < h; ++y) {
  274. for (int x = 0; x < w; ++x) {
  275. *bm->getAddr32(x, y) = get_bitmap_color(x, y, w, ct, at);
  276. }
  277. }
  278. return true;
  279. }
  280. static void call_writepixels(SkSurface* surface) {
  281. const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
  282. SkPMColor pixel = 0;
  283. surface->writePixels({info, &pixel, sizeof(SkPMColor)}, 0, 0);
  284. }
  285. DEF_TEST(WritePixelsSurfaceGenID, reporter) {
  286. const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
  287. auto surface(SkSurface::MakeRaster(info));
  288. uint32_t genID1 = surface->generationID();
  289. call_writepixels(surface.get());
  290. uint32_t genID2 = surface->generationID();
  291. REPORTER_ASSERT(reporter, genID1 != genID2);
  292. }
  293. static void test_write_pixels(skiatest::Reporter* reporter, SkSurface* surface,
  294. const SkImageInfo& surfaceInfo) {
  295. const SkIRect testRects[] = {
  296. // entire thing
  297. DEV_RECT,
  298. // larger on all sides
  299. SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
  300. // fully contained
  301. SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
  302. // outside top left
  303. SkIRect::MakeLTRB(-10, -10, -1, -1),
  304. // touching top left corner
  305. SkIRect::MakeLTRB(-10, -10, 0, 0),
  306. // overlapping top left corner
  307. SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
  308. // overlapping top left and top right corners
  309. SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4),
  310. // touching entire top edge
  311. SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0),
  312. // overlapping top right corner
  313. SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4),
  314. // contained in x, overlapping top edge
  315. SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4),
  316. // outside top right corner
  317. SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
  318. // touching top right corner
  319. SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
  320. // overlapping top left and bottom left corners
  321. SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
  322. // touching entire left edge
  323. SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
  324. // overlapping bottom left corner
  325. SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
  326. // contained in y, overlapping left edge
  327. SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
  328. // outside bottom left corner
  329. SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
  330. // touching bottom left corner
  331. SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
  332. // overlapping bottom left and bottom right corners
  333. SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
  334. // touching entire left edge
  335. SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
  336. // overlapping bottom right corner
  337. SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
  338. // overlapping top right and bottom right corners
  339. SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
  340. };
  341. SkCanvas* canvas = surface->getCanvas();
  342. static const struct {
  343. SkColorType fColorType;
  344. SkAlphaType fAlphaType;
  345. } gSrcConfigs[] = {
  346. {kRGBA_8888_SkColorType, kPremul_SkAlphaType},
  347. {kRGBA_8888_SkColorType, kUnpremul_SkAlphaType},
  348. {kRGB_888x_SkColorType, kOpaque_SkAlphaType},
  349. {kBGRA_8888_SkColorType, kPremul_SkAlphaType},
  350. {kBGRA_8888_SkColorType, kUnpremul_SkAlphaType},
  351. };
  352. for (size_t r = 0; r < SK_ARRAY_COUNT(testRects); ++r) {
  353. const SkIRect& rect = testRects[r];
  354. for (int tightBmp = 0; tightBmp < 2; ++tightBmp) {
  355. for (size_t c = 0; c < SK_ARRAY_COUNT(gSrcConfigs); ++c) {
  356. const SkColorType ct = gSrcConfigs[c].fColorType;
  357. const SkAlphaType at = gSrcConfigs[c].fAlphaType;
  358. bool isGPU = SkToBool(surface->getCanvas()->getGrContext());
  359. fill_surface(surface);
  360. SkBitmap bmp;
  361. REPORTER_ASSERT(reporter, setup_bitmap(&bmp, ct, at, rect.width(),
  362. rect.height(), SkToBool(tightBmp)));
  363. uint32_t idBefore = surface->generationID();
  364. surface->writePixels(bmp, rect.fLeft, rect.fTop);
  365. uint32_t idAfter = surface->generationID();
  366. REPORTER_ASSERT(reporter, check_write(reporter, surface, surfaceInfo.alphaType(),
  367. bmp, rect.fLeft, rect.fTop));
  368. // we should change the genID iff pixels were actually written.
  369. SkIRect canvasRect = SkIRect::MakeSize(canvas->getBaseLayerSize());
  370. SkIRect writeRect = SkIRect::MakeXYWH(rect.fLeft, rect.fTop,
  371. bmp.width(), bmp.height());
  372. bool expectSuccess = SkIRect::Intersects(canvasRect, writeRect) &&
  373. write_should_succeed(surfaceInfo, bmp.info(), isGPU);
  374. REPORTER_ASSERT(reporter, expectSuccess == (idBefore != idAfter));
  375. }
  376. }
  377. }
  378. }
  379. DEF_TEST(WritePixels, reporter) {
  380. const SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
  381. for (auto& tightRowBytes : { true, false }) {
  382. const size_t rowBytes = tightRowBytes ? info.minRowBytes() : 4 * DEV_W + 100;
  383. const size_t size = info.computeByteSize(rowBytes);
  384. void* pixels = sk_malloc_throw(size);
  385. // if rowBytes isn't tight then set the padding to a known value
  386. if (!tightRowBytes) {
  387. memset(pixels, DEV_PAD, size);
  388. }
  389. auto surface(SkSurface::MakeRasterDirectReleaseProc(info, pixels, rowBytes,
  390. free_pixels, nullptr));
  391. test_write_pixels(reporter, surface.get(), info);
  392. }
  393. }
  394. static void test_write_pixels(skiatest::Reporter* reporter, GrContext* context, int sampleCnt) {
  395. const SkImageInfo ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
  396. for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
  397. sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(context,
  398. SkBudgeted::kNo, ii, sampleCnt,
  399. origin, nullptr));
  400. if (surface) {
  401. test_write_pixels(reporter, surface.get(), ii);
  402. }
  403. }
  404. }
  405. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixels_Gpu, reporter, ctxInfo) {
  406. test_write_pixels(reporter, ctxInfo.grContext(), 1);
  407. }
  408. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsMSAA_Gpu, reporter, ctxInfo) {
  409. test_write_pixels(reporter, ctxInfo.grContext(), 1);
  410. }
  411. static void test_write_pixels_non_texture(skiatest::Reporter* reporter,
  412. GrContext* context,
  413. int sampleCnt) {
  414. for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
  415. GrBackendTexture backendTex = context->createBackendTexture(
  416. DEV_W, DEV_H, kRGBA_8888_SkColorType,
  417. SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kYes, GrProtected::kNo);
  418. if (!backendTex.isValid()) {
  419. continue;
  420. }
  421. SkColorType colorType = kN32_SkColorType;
  422. sk_sp<SkSurface> surface(SkSurface::MakeFromBackendTextureAsRenderTarget(
  423. context, backendTex, origin, sampleCnt, colorType, nullptr, nullptr));
  424. if (surface) {
  425. auto ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
  426. test_write_pixels(reporter, surface.get(), ii);
  427. }
  428. context->deleteBackendTexture(backendTex);
  429. }
  430. }
  431. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTexture_Gpu, reporter, ctxInfo) {
  432. test_write_pixels_non_texture(reporter, ctxInfo.grContext(), 1);
  433. }
  434. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTextureMSAA_Gpu, reporter, ctxInfo) {
  435. test_write_pixels_non_texture(reporter, ctxInfo.grContext(), 4);
  436. }
  437. static sk_sp<SkSurface> create_surf(GrContext* context, int width, int height) {
  438. const SkImageInfo ii = SkImageInfo::Make(width, height,
  439. kRGBA_8888_SkColorType, kPremul_SkAlphaType);
  440. sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii);
  441. surf->flush();
  442. return surf;
  443. }
  444. static sk_sp<SkImage> upload(const sk_sp<SkSurface>& surf, SkColor color) {
  445. const SkImageInfo smII = SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
  446. SkBitmap bm;
  447. bm.allocPixels(smII);
  448. bm.eraseColor(color);
  449. surf->writePixels(bm, 0, 0);
  450. return surf->makeImageSnapshot();
  451. }
  452. // This is tests whether the first writePixels is completed before the
  453. // second writePixels takes effect (i.e., that writePixels correctly flushes
  454. // in between uses of the shared backing resource).
  455. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsPendingIO, reporter, ctxInfo) {
  456. GrContext* context = ctxInfo.grContext();
  457. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  458. static const int kFullSize = 62;
  459. static const int kHalfSize = 31;
  460. static const uint32_t kLeftColor = 0xFF222222;
  461. static const uint32_t kRightColor = 0xFFAAAAAA;
  462. const SkImageInfo fullII = SkImageInfo::Make(kFullSize, kFullSize,
  463. kRGBA_8888_SkColorType, kPremul_SkAlphaType);
  464. const SkImageInfo halfII = SkImageInfo::Make(kHalfSize, kFullSize,
  465. kRGBA_8888_SkColorType, kPremul_SkAlphaType);
  466. sk_sp<SkSurface> dest = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, fullII);
  467. {
  468. // Seed the resource cached with a scratch texture that will be reused by writePixels
  469. GrSurfaceDesc desc;
  470. desc.fWidth = 32;
  471. desc.fHeight = 64;
  472. desc.fConfig = kRGBA_8888_GrPixelConfig;
  473. const GrBackendFormat format =
  474. context->priv().caps()->getBackendFormatFromColorType(GrColorType::kRGBA_8888);
  475. sk_sp<GrTextureProxy> temp = proxyProvider->createProxy(
  476. format, desc, GrRenderable::kNo, 1, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox,
  477. SkBudgeted::kYes, GrProtected::kNo);
  478. temp->instantiate(context->priv().resourceProvider());
  479. }
  480. // Create the surfaces and flush them to ensure there is no lingering pendingIO
  481. sk_sp<SkSurface> leftSurf = create_surf(context, kHalfSize, kFullSize);
  482. sk_sp<SkSurface> rightSurf = create_surf(context, kHalfSize, kFullSize);
  483. sk_sp<SkImage> leftImg = upload(std::move(leftSurf), kLeftColor);
  484. dest->getCanvas()->drawImage(std::move(leftImg), 0, 0);
  485. sk_sp<SkImage> rightImg = upload(std::move(rightSurf), kRightColor);
  486. dest->getCanvas()->drawImage(std::move(rightImg), kHalfSize, 0);
  487. SkBitmap bm;
  488. bm.allocPixels(fullII);
  489. SkAssertResult(dest->readPixels(bm, 0, 0));
  490. bool isCorrect = true;
  491. for (int y = 0; isCorrect && y < 16; ++y) {
  492. const uint32_t* sl = bm.getAddr32(0, y);
  493. for (int x = 0; x < 16; ++x) {
  494. if (kLeftColor != sl[x]) {
  495. isCorrect = false;
  496. break;
  497. }
  498. }
  499. for (int x = kHalfSize; x < kHalfSize+16; ++x) {
  500. if (kRightColor != sl[x]) {
  501. isCorrect = false;
  502. break;
  503. }
  504. }
  505. }
  506. REPORTER_ASSERT(reporter, isCorrect);
  507. }