• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 "tests/TestUtils.h"
9 
10 #include "include/encode/SkPngEncoder.h"
11 #include "include/utils/SkBase64.h"
12 #include "src/core/SkAutoPixmapStorage.h"
13 #include "src/core/SkUtils.h"
14 #include "src/gpu/GrDirectContextPriv.h"
15 #include "src/gpu/GrDrawingManager.h"
16 #include "src/gpu/GrGpu.h"
17 #include "src/gpu/GrImageInfo.h"
18 #include "src/gpu/GrRecordingContextPriv.h"
19 #include "src/gpu/GrSurfaceContext.h"
20 #include "src/gpu/GrSurfaceProxy.h"
21 #include "src/gpu/GrTextureProxy.h"
22 #include "src/gpu/SkGr.h"
23 
TestReadPixels(skiatest::Reporter * reporter,GrDirectContext * dContext,GrSurfaceContext * srcContext,uint32_t expectedPixelValues[],const char * testName)24 void TestReadPixels(skiatest::Reporter* reporter,
25                     GrDirectContext* dContext,
26                     GrSurfaceContext* srcContext,
27                     uint32_t expectedPixelValues[],
28                     const char* testName) {
29     int pixelCnt = srcContext->width() * srcContext->height();
30     SkImageInfo ii = SkImageInfo::Make(srcContext->dimensions(),
31                                        kRGBA_8888_SkColorType,
32                                        kPremul_SkAlphaType);
33     SkAutoPixmapStorage pm;
34     pm.alloc(ii);
35     pm.erase(SK_ColorTRANSPARENT);
36 
37     bool read = srcContext->readPixels(dContext, pm, {0, 0});
38     if (!read) {
39         ERRORF(reporter, "%s: Error reading from texture.", testName);
40     }
41 
42     for (int i = 0; i < pixelCnt; ++i) {
43         if (pm.addr32()[i] != expectedPixelValues[i]) {
44             ERRORF(reporter, "%s: Error, pixel value %d should be 0x%08x, got 0x%08x.",
45                    testName, i, expectedPixelValues[i], pm.addr32()[i]);
46             break;
47         }
48     }
49 }
50 
TestWritePixels(skiatest::Reporter * reporter,GrDirectContext * dContext,GrSurfaceContext * dstContext,bool expectedToWork,const char * testName)51 void TestWritePixels(skiatest::Reporter* reporter,
52                      GrDirectContext* dContext,
53                      GrSurfaceContext* dstContext,
54                      bool expectedToWork,
55                      const char* testName) {
56     SkImageInfo ii = SkImageInfo::Make(dstContext->dimensions(),
57                                        kRGBA_8888_SkColorType,
58                                        kPremul_SkAlphaType);
59     SkAutoPixmapStorage pm;
60     pm.alloc(ii);
61     for (int y = 0; y < dstContext->height(); ++y) {
62         for (int x = 0; x < dstContext->width(); ++x) {
63             *pm.writable_addr32(x, y) = SkColorToPremulGrColor(SkColorSetARGB(2*y, x, y, x + y));
64         }
65     }
66 
67     bool write = dstContext->writePixels(dContext, pm, {0, 0});
68     if (!write) {
69         if (expectedToWork) {
70             ERRORF(reporter, "%s: Error writing to texture.", testName);
71         }
72         return;
73     }
74 
75     if (write && !expectedToWork) {
76         ERRORF(reporter, "%s: writePixels succeeded when it wasn't supposed to.", testName);
77         return;
78     }
79 
80     TestReadPixels(reporter, dContext, dstContext, pm.writable_addr32(0, 0), testName);
81 }
82 
TestCopyFromSurface(skiatest::Reporter * reporter,GrDirectContext * dContext,sk_sp<GrSurfaceProxy> proxy,GrSurfaceOrigin origin,GrColorType colorType,uint32_t expectedPixelValues[],const char * testName)83 void TestCopyFromSurface(skiatest::Reporter* reporter,
84                          GrDirectContext* dContext,
85                          sk_sp<GrSurfaceProxy> proxy,
86                          GrSurfaceOrigin origin,
87                          GrColorType colorType,
88                          uint32_t expectedPixelValues[],
89                          const char* testName) {
90     auto copy = GrSurfaceProxy::Copy(dContext, std::move(proxy), origin, GrMipmapped::kNo,
91                                      SkBackingFit::kExact, SkBudgeted::kYes);
92     SkASSERT(copy && copy->asTextureProxy());
93     auto swizzle = dContext->priv().caps()->getReadSwizzle(copy->backendFormat(), colorType);
94     GrSurfaceProxyView view(std::move(copy), origin, swizzle);
95     auto dstContext = GrSurfaceContext::Make(dContext,
96                                              std::move(view),
97                                              {colorType, kPremul_SkAlphaType, nullptr});
98     SkASSERT(dstContext);
99 
100     TestReadPixels(reporter, dContext, dstContext.get(), expectedPixelValues, testName);
101 }
102 
BipmapToBase64DataURI(const SkBitmap & bitmap,SkString * dst)103 bool BipmapToBase64DataURI(const SkBitmap& bitmap, SkString* dst) {
104     SkPixmap pm;
105     if (!bitmap.peekPixels(&pm)) {
106         dst->set("peekPixels failed");
107         return false;
108     }
109 
110     // We're going to embed this PNG in a data URI, so make it as small as possible
111     SkPngEncoder::Options options;
112     options.fFilterFlags = SkPngEncoder::FilterFlag::kAll;
113     options.fZLibLevel = 9;
114 
115     SkDynamicMemoryWStream wStream;
116     if (!SkPngEncoder::Encode(&wStream, pm, options)) {
117         dst->set("SkPngEncoder::Encode failed");
118         return false;
119     }
120 
121     sk_sp<SkData> pngData = wStream.detachAsData();
122     size_t len = SkBase64::Encode(pngData->data(), pngData->size(), nullptr);
123 
124     // The PNG can be almost arbitrarily large. We don't want to fill our logs with enormous URLs.
125     // Infra says these can be pretty big, as long as we're only outputting them on failure.
126     static const size_t kMaxBase64Length = 1024 * 1024;
127     if (len > kMaxBase64Length) {
128         dst->printf("Encoded image too large (%u bytes)", static_cast<uint32_t>(len));
129         return false;
130     }
131 
132     dst->resize(len);
133     SkBase64::Encode(pngData->data(), pngData->size(), dst->writable_str());
134     dst->prepend("data:image/png;base64,");
135     return true;
136 }
137 
compare_colors(int x,int y,const float rgbaA[],const float rgbaB[],const float tolRGBA[4],std::function<ComparePixmapsErrorReporter> & error)138 static bool compare_colors(int x, int y,
139                            const float rgbaA[],
140                            const float rgbaB[],
141                            const float tolRGBA[4],
142                            std::function<ComparePixmapsErrorReporter>& error) {
143     float diffs[4];
144     bool bad = false;
145     for (int i = 0; i < 4; ++i) {
146         diffs[i] = rgbaB[i] - rgbaA[i];
147         if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
148             bad = true;
149         }
150     }
151     if (bad) {
152         error(x, y, diffs);
153         return false;
154     }
155     return true;
156 }
157 
ComparePixels(const GrCPixmap & a,const GrCPixmap & b,const float tolRGBA[4],std::function<ComparePixmapsErrorReporter> & error)158 bool ComparePixels(const GrCPixmap& a,
159                    const GrCPixmap& b,
160                    const float tolRGBA[4],
161                    std::function<ComparePixmapsErrorReporter>& error) {
162     if (a.dimensions() != b.dimensions()) {
163         static constexpr float kDummyDiffs[4] = {};
164         error(-1, -1, kDummyDiffs);
165         return false;
166     }
167 
168     SkAlphaType floatAlphaType = a.alphaType();
169     // If one is premul and the other is unpremul we do the comparison in premul space.
170     if ((a.alphaType() == kPremul_SkAlphaType   || b.alphaType() == kPremul_SkAlphaType) &&
171         (a.alphaType() == kUnpremul_SkAlphaType || b.alphaType() == kUnpremul_SkAlphaType)) {
172         floatAlphaType = kPremul_SkAlphaType;
173     }
174     sk_sp<SkColorSpace> floatCS;
175     if (SkColorSpace::Equals(a.colorSpace(), b.colorSpace())) {
176         floatCS = a.refColorSpace();
177     } else {
178         floatCS = SkColorSpace::MakeSRGBLinear();
179     }
180     GrImageInfo floatInfo(GrColorType::kRGBA_F32,
181                           floatAlphaType,
182                           std::move(floatCS),
183                           a.dimensions());
184 
185     GrPixmap floatA = GrPixmap::Allocate(floatInfo);
186     GrPixmap floatB = GrPixmap::Allocate(floatInfo);
187     SkAssertResult(GrConvertPixels(floatA, a));
188     SkAssertResult(GrConvertPixels(floatB, b));
189 
190     SkASSERT(floatA.rowBytes() == floatB.rowBytes());
191     auto at = [rb = floatA.rowBytes()](const void* base, int x, int y) {
192         return SkTAddOffset<const float>(base, y*rb + x*sizeof(float)*4);
193     };
194 
195     for (int y = 0; y < floatA.height(); ++y) {
196         for (int x = 0; x < floatA.width(); ++x) {
197             const float* rgbaA = at(floatA.addr(), x, y);
198             const float* rgbaB = at(floatB.addr(), x, y);
199             if (!compare_colors(x, y, rgbaA, rgbaB, tolRGBA, error)) {
200                 return false;
201             }
202         }
203     }
204     return true;
205 }
206 
CheckSolidPixels(const SkColor4f & col,const SkPixmap & pixmap,const float tolRGBA[4],std::function<ComparePixmapsErrorReporter> & error)207 bool CheckSolidPixels(const SkColor4f& col,
208                       const SkPixmap& pixmap,
209                       const float tolRGBA[4],
210                       std::function<ComparePixmapsErrorReporter>& error) {
211     size_t floatBpp = GrColorTypeBytesPerPixel(GrColorType::kRGBA_F32);
212 
213     // First convert 'col' to be compatible with 'pixmap'
214     GrPixmap colorPixmap;
215     {
216         sk_sp<SkColorSpace> srcCS = SkColorSpace::MakeSRGBLinear();
217         GrImageInfo srcInfo(GrColorType::kRGBA_F32,
218                             kUnpremul_SkAlphaType,
219                             std::move(srcCS),
220                             {1, 1});
221         GrCPixmap srcPixmap(srcInfo, col.vec(), floatBpp);
222         GrImageInfo dstInfo =
223                 srcInfo.makeAlphaType(pixmap.alphaType()).makeColorSpace(pixmap.refColorSpace());
224         colorPixmap = GrPixmap::Allocate(dstInfo);
225         SkAssertResult(GrConvertPixels(colorPixmap, srcPixmap));
226     }
227 
228     size_t floatRowBytes = floatBpp * pixmap.width();
229     std::unique_ptr<char[]> floatB(new char[floatRowBytes * pixmap.height()]);
230     // Then convert 'pixmap' to RGBA_F32
231     GrPixmap f32Pixmap = GrPixmap::Allocate(pixmap.info().makeColorType(kRGBA_F32_SkColorType));
232     SkAssertResult(GrConvertPixels(f32Pixmap, pixmap));
233 
234     for (int y = 0; y < f32Pixmap.height(); ++y) {
235         for (int x = 0; x < f32Pixmap.width(); ++x) {
236             auto rgbaA = SkTAddOffset<const float>(f32Pixmap.addr(),
237                                                    f32Pixmap.rowBytes()*y + floatBpp*x);
238             auto rgbaB = static_cast<const float*>(colorPixmap.addr());
239             if (!compare_colors(x, y, rgbaA, rgbaB, tolRGBA, error)) {
240                 return false;
241             }
242         }
243     }
244     return true;
245 }
246 
CheckSingleThreadedProxyRefs(skiatest::Reporter * reporter,GrSurfaceProxy * proxy,int32_t expectedProxyRefs,int32_t expectedBackingRefs)247 void CheckSingleThreadedProxyRefs(skiatest::Reporter* reporter,
248                                   GrSurfaceProxy* proxy,
249                                   int32_t expectedProxyRefs,
250                                   int32_t expectedBackingRefs) {
251     int32_t actualBackingRefs = proxy->testingOnly_getBackingRefCnt();
252 
253     REPORTER_ASSERT(reporter, proxy->refCntGreaterThan(expectedProxyRefs - 1) &&
254                               !proxy->refCntGreaterThan(expectedProxyRefs));
255     REPORTER_ASSERT(reporter, actualBackingRefs == expectedBackingRefs);
256 }
257 
258 #include "src/utils/SkCharToGlyphCache.h"
259 
hash_to_glyph(uint32_t value)260 static SkGlyphID hash_to_glyph(uint32_t value) {
261     return SkToU16(((value >> 16) ^ value) & 0xFFFF);
262 }
263 
264 namespace {
265 class UnicharGen {
266     SkUnichar fU;
267     const int fStep;
268 public:
UnicharGen(int step)269     UnicharGen(int step) : fU(0), fStep(step) {}
270 
next()271     SkUnichar next() {
272         fU += fStep;
273         return fU;
274     }
275 };
276 }  // namespace
277 
DEF_TEST(chartoglyph_cache,reporter)278 DEF_TEST(chartoglyph_cache, reporter) {
279     SkCharToGlyphCache cache;
280     const int step = 3;
281 
282     UnicharGen gen(step);
283     for (int i = 0; i < 500; ++i) {
284         SkUnichar c = gen.next();
285         SkGlyphID glyph = hash_to_glyph(c);
286 
287         int index = cache.findGlyphIndex(c);
288         if (index >= 0) {
289             index = cache.findGlyphIndex(c);
290         }
291         REPORTER_ASSERT(reporter, index < 0);
292         cache.insertCharAndGlyph(~index, c, glyph);
293 
294         UnicharGen gen2(step);
295         for (int j = 0; j <= i; ++j) {
296             c = gen2.next();
297             glyph = hash_to_glyph(c);
298             index = cache.findGlyphIndex(c);
299             if ((unsigned)index != glyph) {
300                 index = cache.findGlyphIndex(c);
301             }
302             REPORTER_ASSERT(reporter, (unsigned)index == glyph);
303         }
304     }
305 }
306