scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 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 | |
scroggo@google.com | 825bb95 | 2012-08-22 15:14:43 +0000 | [diff] [blame] | 9 | #if SK_SUPPORT_GPU |
| 10 | |
scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 11 | #include "GrContext.h" |
| 12 | #include "SkBitmap.h" |
scroggo@google.com | a2a3192 | 2012-12-07 19:14:45 +0000 | [diff] [blame] | 13 | #include "SkCanvas.h" |
| 14 | #include "SkColor.h" |
scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 15 | #include "SkGpuDevice.h" |
scroggo@google.com | a2a3192 | 2012-12-07 19:14:45 +0000 | [diff] [blame] | 16 | #include "SkPaint.h" |
scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 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 | |
scroggo@google.com | a2a3192 | 2012-12-07 19:14:45 +0000 | [diff] [blame] | 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 | |
scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 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) { |
bsalomon@google.com | 7f805ff | 2012-12-10 17:32:07 +0000 | [diff] [blame] | 121 | #ifdef SK_BUILD_FOR_ANDROID // https://code.google.com/p/skia/issues/detail?id=753 |
| 122 | return; |
| 123 | #endif |
scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 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++) { |
scroggo@google.com | a2a3192 | 2012-12-07 19:14:45 +0000 | [diff] [blame] | 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 | |
scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 159 | for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) { |
scroggo@google.com | a2a3192 | 2012-12-07 19:14:45 +0000 | [diff] [blame] | 160 | dst.reset(); |
scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 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 | |
scroggo@google.com | a2a3192 | 2012-12-07 19:14:45 +0000 | [diff] [blame] | 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); |
scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 199 | } |
| 200 | } // for (size_t j = ... |
scroggo@google.com | a2a3192 | 2012-12-07 19:14:45 +0000 | [diff] [blame] | 201 | } // for (size_t i = ... |
scroggo@google.com | d5764e8 | 2012-08-22 15:00:05 +0000 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | #include "TestClassDef.h" |
| 205 | DEFINE_GPUTESTCLASS("GpuBitmapCopy", TestGpuBitmapCopyClass, TestGpuBitmapCopy) |
scroggo@google.com | 825bb95 | 2012-08-22 15:14:43 +0000 | [diff] [blame] | 206 | |
| 207 | #endif |