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