Home | History | Annotate | Download | only in tests
      1 
      2 /*
      3  * Copyright 2012 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 #if SK_SUPPORT_GPU
     10 
     11 #include "GrContext.h"
     12 #include "SkBitmap.h"
     13 #include "SkCanvas.h"
     14 #include "SkColor.h"
     15 #include "SkGpuDevice.h"
     16 #include "SkPaint.h"
     17 #include "SkPixelRef.h"
     18 #include "SkRect.h"
     19 #include "Test.h"
     20 
     21 static const char* boolStr(bool value) {
     22     return value ? "true" : "false";
     23 }
     24 
     25 // these are in the same order as the SkBitmap::Config enum
     26 static const char* gConfigName[] = {
     27     "None", "4444", "8888"
     28 };
     29 
     30 struct Pair {
     31     SkBitmap::Config    fConfig;
     32     const char*         fValid;
     33 };
     34 
     35 extern bool getUpperLeftFromOffset(const SkBitmap& bm, int* x, int* y);
     36 extern size_t getSubOffset(const SkBitmap& bm, int x, int y);
     37 
     38 /**
     39  *  Tests that getUpperLeftFromOffset and getSubOffset agree with each other.
     40  */
     41 static void TestSubsetHelpers(skiatest::Reporter* reporter, const SkBitmap& bitmap){
     42     int x, y;
     43     bool upperLeft = getUpperLeftFromOffset(bitmap, &x, &y);
     44     REPORTER_ASSERT(reporter, upperLeft);
     45     REPORTER_ASSERT(reporter, getSubOffset(bitmap, x, y) == bitmap.pixelRefOffset());
     46 }
     47 
     48 /**
     49  *  Check to ensure that copying a GPU-backed SkBitmap behaved as expected.
     50  *  @param reporter Used to report failures.
     51  *  @param desiredConfig Config being copied to. If the copy succeeded, dst must have this Config.
     52  *  @param success True if the copy succeeded.
     53  *  @param src A GPU-backed SkBitmap that had copyTo or deepCopyTo called on it.
     54  *  @param dst SkBitmap that was copied to.
     55  *  @param deepCopy True if deepCopyTo was used; false if copyTo was used.
     56  *  @param subset Portion of src's SkPixelRef that src represents. dst should represent the same
     57  *      portion after the copy. Pass NULL for all pixels.
     58  */
     59 static void TestIndividualCopy(skiatest::Reporter* reporter, const SkBitmap::Config desiredConfig,
     60                                const bool success, const SkBitmap& src, const SkBitmap& dst,
     61                                const bool deepCopy = true, const SkIRect* subset = NULL) {
     62     if (success) {
     63         REPORTER_ASSERT(reporter, src.width() == dst.width());
     64         REPORTER_ASSERT(reporter, src.height() == dst.height());
     65         REPORTER_ASSERT(reporter, dst.config() == desiredConfig);
     66         if (src.config() == dst.config()) {
     67             // FIXME: When calling copyTo (so deepCopy is false here), sometimes we copy the pixels
     68             // exactly, in which case the IDs should be the same, but sometimes we do a bitmap draw,
     69             // in which case the IDs should not be the same. Is there any way to determine which is
     70             // the case at this point?
     71             if (deepCopy) {
     72                 REPORTER_ASSERT(reporter, src.getGenerationID() == dst.getGenerationID());
     73             }
     74             REPORTER_ASSERT(reporter, src.pixelRef() != NULL && dst.pixelRef() != NULL);
     75 
     76             // Do read backs and make sure that the two are the same.
     77             SkBitmap srcReadBack, dstReadBack;
     78             {
     79                 SkASSERT(src.getTexture() != NULL);
     80                 bool readBack = src.pixelRef()->readPixels(&srcReadBack, subset);
     81                 REPORTER_ASSERT(reporter, readBack);
     82             }
     83             if (dst.getTexture() != NULL) {
     84                 bool readBack = dst.pixelRef()->readPixels(&dstReadBack, subset);
     85                 REPORTER_ASSERT(reporter, readBack);
     86             } else {
     87                 // If dst is not a texture, do a copy instead, to the same config as srcReadBack.
     88                 bool copy = dst.copyTo(&dstReadBack, srcReadBack.config());
     89                 REPORTER_ASSERT(reporter, copy);
     90             }
     91 
     92             SkAutoLockPixels srcLock(srcReadBack);
     93             SkAutoLockPixels dstLock(dstReadBack);
     94             REPORTER_ASSERT(reporter, srcReadBack.readyToDraw() && dstReadBack.readyToDraw());
     95 
     96             const char* srcP = static_cast<const char*>(srcReadBack.getAddr(0, 0));
     97             const char* dstP = static_cast<const char*>(dstReadBack.getAddr(0, 0));
     98             REPORTER_ASSERT(reporter, srcP != dstP);
     99 
    100             REPORTER_ASSERT(reporter, !memcmp(srcP, dstP, srcReadBack.getSize()));
    101         } else {
    102             REPORTER_ASSERT(reporter, src.getGenerationID() != dst.getGenerationID());
    103         }
    104 
    105         // If the copy used a subset, test the pixel offset calculation functions.
    106         if (subset != NULL) {
    107             TestSubsetHelpers(reporter, dst);
    108         }
    109     } else {
    110         // dst should be unchanged from its initial state
    111         REPORTER_ASSERT(reporter, dst.config() == SkBitmap::kNo_Config);
    112         REPORTER_ASSERT(reporter, dst.width() == 0);
    113         REPORTER_ASSERT(reporter, dst.height() == 0);
    114     }
    115 
    116 }
    117 
    118 // Stripped down version of TestBitmapCopy that checks basic fields (width, height, config, genID)
    119 // to ensure that they were copied properly.
    120 static void TestGpuBitmapCopy(skiatest::Reporter* reporter, GrContext* grContext) {
    121 #ifdef SK_BUILD_FOR_ANDROID // https://code.google.com/p/skia/issues/detail?id=753
    122     return;
    123 #endif
    124     if (NULL == grContext) {
    125         return;
    126     }
    127     static const Pair gPairs[] = {
    128         { SkBitmap::kNo_Config,         "000"  },
    129         { SkBitmap::kARGB_4444_Config,  "011"  },
    130         { SkBitmap::kARGB_8888_Config,  "011"  },
    131     };
    132 
    133     const int W = 20;
    134     const int H = 33;
    135 
    136     for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
    137         SkBitmap src, dst;
    138 
    139         SkGpuDevice* device = SkNEW_ARGS(SkGpuDevice, (grContext, gPairs[i].fConfig, W, H));
    140         SkAutoUnref aur(device);
    141         src = device->accessBitmap(false);
    142         device->clear(SK_ColorWHITE);
    143 
    144         // Draw something different to the same portion of the bitmap that we will extract as a
    145         // subset, so that comparing the pixels of the subset will be meaningful.
    146         SkIRect subsetRect = SkIRect::MakeLTRB(W/2, H/2, W, H);
    147         SkCanvas drawingCanvas(device);
    148         SkPaint paint;
    149         paint.setColor(SK_ColorRED);
    150         drawingCanvas.drawRect(SkRect::MakeFromIRect(subsetRect), paint);
    151 
    152         // Extract a subset. If this succeeds we will test copying the subset.
    153         SkBitmap subset;
    154         const bool extracted = src.extractSubset(&subset, subsetRect);
    155         if (extracted) {
    156             TestSubsetHelpers(reporter, subset);
    157         }
    158 
    159         for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
    160             dst.reset();
    161             bool success = src.deepCopyTo(&dst, gPairs[j].fConfig);
    162             bool expected = gPairs[i].fValid[j] != '0';
    163             if (success != expected) {
    164                 SkString str;
    165                 str.printf("SkBitmap::deepCopyTo from %s to %s. expected %s returned %s",
    166                            gConfigName[i], gConfigName[j], boolStr(expected),
    167                            boolStr(success));
    168                 reporter->reportFailed(str);
    169             }
    170 
    171             bool canSucceed = src.canCopyTo(gPairs[j].fConfig);
    172             if (success != canSucceed) {
    173                 SkString str;
    174                 str.printf("SkBitmap::deepCopyTo from %s to %s returned %s,"
    175                            "but canCopyTo returned %s",
    176                            gConfigName[i], gConfigName[j], boolStr(success),
    177                            boolStr(canSucceed));
    178                 reporter->reportFailed(str);
    179             }
    180 
    181             TestIndividualCopy(reporter, gPairs[j].fConfig, success, src, dst);
    182 
    183             // Test copying the subset bitmap, using both copyTo and deepCopyTo.
    184             if (extracted) {
    185                 SkBitmap subsetCopy;
    186                 success = subset.copyTo(&subsetCopy, gPairs[j].fConfig);
    187                 REPORTER_ASSERT(reporter, success == expected);
    188                 REPORTER_ASSERT(reporter, success == canSucceed);
    189                 TestIndividualCopy(reporter, gPairs[j].fConfig, success, subset, subsetCopy, false,
    190                                    &subsetRect);
    191 
    192                 // Reset the bitmap so that a failed copyTo will leave it in the expected state.
    193                 subsetCopy.reset();
    194                 success = subset.deepCopyTo(&subsetCopy, gPairs[j].fConfig);
    195                 REPORTER_ASSERT(reporter, success == expected);
    196                 REPORTER_ASSERT(reporter, success == canSucceed);
    197                 TestIndividualCopy(reporter, gPairs[j].fConfig, success, subset, subsetCopy, true,
    198                                    &subsetRect);
    199             }
    200         } // for (size_t j = ...
    201     } // for (size_t i = ...
    202 }
    203 
    204 #include "TestClassDef.h"
    205 DEFINE_GPUTESTCLASS("GpuBitmapCopy", TestGpuBitmapCopyClass, TestGpuBitmapCopy)
    206 
    207 #endif
    208