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