• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
boolStr(bool value)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  */
TestSubsetHelpers(skiatest::Reporter * reporter,const SkBitmap & bitmap)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  */
TestIndividualCopy(skiatest::Reporter * reporter,const SkBitmap::Config desiredConfig,const bool success,const SkBitmap & src,const SkBitmap & dst,const bool deepCopy=true,const SkIRect * subset=NULL)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.
TestGpuBitmapCopy(skiatest::Reporter * reporter,GrContext * grContext)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