• 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/SkUtils.h"
13 #include "src/gpu/GrContextPriv.h"
14 #include "src/gpu/GrDrawingManager.h"
15 #include "src/gpu/GrGpu.h"
16 #include "src/gpu/GrSurfaceContext.h"
17 #include "src/gpu/GrSurfaceProxy.h"
18 #include "src/gpu/GrTextureContext.h"
19 #include "src/gpu/GrTextureProxy.h"
20 #include "src/gpu/SkGr.h"
21 
test_read_pixels(skiatest::Reporter * reporter,GrSurfaceContext * srcContext,uint32_t expectedPixelValues[],const char * testName)22 void test_read_pixels(skiatest::Reporter* reporter,
23                       GrSurfaceContext* srcContext, uint32_t expectedPixelValues[],
24                       const char* testName) {
25     int pixelCnt = srcContext->width() * srcContext->height();
26     SkAutoTMalloc<uint32_t> pixels(pixelCnt);
27     memset(pixels.get(), 0, sizeof(uint32_t)*pixelCnt);
28 
29     SkImageInfo ii = SkImageInfo::Make(srcContext->width(), srcContext->height(),
30                                        kRGBA_8888_SkColorType, kPremul_SkAlphaType);
31     bool read = srcContext->readPixels(ii, pixels.get(), 0, {0, 0});
32     if (!read) {
33         ERRORF(reporter, "%s: Error reading from texture.", testName);
34     }
35 
36     for (int i = 0; i < pixelCnt; ++i) {
37         if (pixels.get()[i] != expectedPixelValues[i]) {
38             ERRORF(reporter, "%s: Error, pixel value %d should be 0x%08x, got 0x%08x.",
39                    testName, i, expectedPixelValues[i], pixels.get()[i]);
40             break;
41         }
42     }
43 }
44 
test_write_pixels(skiatest::Reporter * reporter,GrSurfaceContext * dstContext,bool expectedToWork,const char * testName)45 void test_write_pixels(skiatest::Reporter* reporter,
46                        GrSurfaceContext* dstContext, bool expectedToWork,
47                        const char* testName) {
48     int pixelCnt = dstContext->width() * dstContext->height();
49     SkAutoTMalloc<uint32_t> pixels(pixelCnt);
50     for (int y = 0; y < dstContext->width(); ++y) {
51         for (int x = 0; x < dstContext->height(); ++x) {
52             pixels.get()[y * dstContext->width() + x] =
53                 SkColorToPremulGrColor(SkColorSetARGB(2*y, x, y, x + y));
54         }
55     }
56 
57     SkImageInfo ii = SkImageInfo::Make(dstContext->width(), dstContext->height(),
58                                        kRGBA_8888_SkColorType, kPremul_SkAlphaType);
59     bool write = dstContext->writePixels(ii, pixels.get(), 0, {0, 0});
60     if (!write) {
61         if (expectedToWork) {
62             ERRORF(reporter, "%s: Error writing to texture.", testName);
63         }
64         return;
65     }
66 
67     if (write && !expectedToWork) {
68         ERRORF(reporter, "%s: writePixels succeeded when it wasn't supposed to.", testName);
69         return;
70     }
71 
72     test_read_pixels(reporter, dstContext, pixels.get(), testName);
73 }
74 
test_copy_from_surface(skiatest::Reporter * reporter,GrContext * context,GrSurfaceProxy * proxy,GrColorType colorType,uint32_t expectedPixelValues[],const char * testName)75 void test_copy_from_surface(skiatest::Reporter* reporter, GrContext* context, GrSurfaceProxy* proxy,
76                             GrColorType colorType, uint32_t expectedPixelValues[],
77                             const char* testName) {
78     sk_sp<GrTextureProxy> dstProxy = GrSurfaceProxy::Copy(context, proxy, GrMipMapped::kNo,
79                                                           SkBackingFit::kExact, SkBudgeted::kYes);
80     SkASSERT(dstProxy);
81 
82     sk_sp<GrSurfaceContext> dstContext = context->priv().makeWrappedSurfaceContext(
83             std::move(dstProxy), colorType, kPremul_SkAlphaType);
84     SkASSERT(dstContext.get());
85 
86     test_read_pixels(reporter, dstContext.get(), expectedPixelValues, testName);
87 }
88 
fill_pixel_data(int width,int height,GrColor * data)89 void fill_pixel_data(int width, int height, GrColor* data) {
90     for (int j = 0; j < height; ++j) {
91         for (int i = 0; i < width; ++i) {
92             unsigned int red = (unsigned int)(256.f * (i / (float)width));
93             unsigned int green = (unsigned int)(256.f * (j / (float)height));
94             data[i + j * width] = GrColorPackRGBA(red - (red >> 8), green - (green >> 8),
95                                                   0xff, 0xff);
96         }
97     }
98 }
99 
create_backend_texture(GrContext * context,GrBackendTexture * backendTex,const SkImageInfo & ii,const SkColor4f & color,GrMipMapped mipMapped,GrRenderable renderable)100 bool create_backend_texture(GrContext* context, GrBackendTexture* backendTex,
101                             const SkImageInfo& ii, const SkColor4f& color,
102                             GrMipMapped mipMapped, GrRenderable renderable) {
103     // TODO: use the color-init version of createBackendTexture once Metal supports it.
104 #if 0
105     *backendTex = context->createBackendTexture(ii.width(), ii.height(), ii.colorType(),
106                                                 color, mipMapped, renderable);
107 #else
108     SkBitmap bm;
109     bm.allocPixels(ii);
110     sk_memset32(bm.getAddr32(0, 0), color.toSkColor(), ii.width() * ii.height());
111 
112     SkASSERT(GrMipMapped::kNo == mipMapped);
113     *backendTex = context->priv().createBackendTexture(&bm.pixmap(), 1, renderable,
114                                                        GrProtected::kNo);
115 #endif
116 
117     return backendTex->isValid();
118 }
119 
delete_backend_texture(GrContext * context,const GrBackendTexture & backendTex)120 void delete_backend_texture(GrContext* context, const GrBackendTexture& backendTex) {
121     GrFlushInfo flushInfo;
122     flushInfo.fFlags = kSyncCpu_GrFlushFlag;
123     context->flush(flushInfo);
124     context->deleteBackendTexture(backendTex);
125 }
126 
does_full_buffer_contain_correct_color(const GrColor * srcBuffer,const GrColor * dstBuffer,int width,int height)127 bool does_full_buffer_contain_correct_color(const GrColor* srcBuffer,
128                                             const GrColor* dstBuffer,
129                                             int width,
130                                             int height) {
131     const GrColor* srcPtr = srcBuffer;
132     const GrColor* dstPtr = dstBuffer;
133     for (int j = 0; j < height; ++j) {
134         for (int i = 0; i < width; ++i) {
135             if (srcPtr[i] != dstPtr[i]) {
136                 return false;
137             }
138         }
139         srcPtr += width;
140         dstPtr += width;
141     }
142     return true;
143 }
144 
bitmap_to_base64_data_uri(const SkBitmap & bitmap,SkString * dst)145 bool bitmap_to_base64_data_uri(const SkBitmap& bitmap, SkString* dst) {
146     SkPixmap pm;
147     if (!bitmap.peekPixels(&pm)) {
148         dst->set("peekPixels failed");
149         return false;
150     }
151 
152     // We're going to embed this PNG in a data URI, so make it as small as possible
153     SkPngEncoder::Options options;
154     options.fFilterFlags = SkPngEncoder::FilterFlag::kAll;
155     options.fZLibLevel = 9;
156 
157     SkDynamicMemoryWStream wStream;
158     if (!SkPngEncoder::Encode(&wStream, pm, options)) {
159         dst->set("SkPngEncoder::Encode failed");
160         return false;
161     }
162 
163     sk_sp<SkData> pngData = wStream.detachAsData();
164     size_t len = SkBase64::Encode(pngData->data(), pngData->size(), nullptr);
165 
166     // The PNG can be almost arbitrarily large. We don't want to fill our logs with enormous URLs.
167     // Infra says these can be pretty big, as long as we're only outputting them on failure.
168     static const size_t kMaxBase64Length = 1024 * 1024;
169     if (len > kMaxBase64Length) {
170         dst->printf("Encoded image too large (%u bytes)", static_cast<uint32_t>(len));
171         return false;
172     }
173 
174     dst->resize(len);
175     SkBase64::Encode(pngData->data(), pngData->size(), dst->writable_str());
176     dst->prepend("data:image/png;base64,");
177     return true;
178 }
179 
compare_pixels(const GrPixelInfo & infoA,const char * a,size_t rowBytesA,const GrPixelInfo & infoB,const char * b,size_t rowBytesB,const float tolRGBA[4],std::function<ComparePixmapsErrorReporter> & error)180 bool compare_pixels(const GrPixelInfo& infoA, const char* a, size_t rowBytesA,
181                     const GrPixelInfo& infoB, const char* b, size_t rowBytesB,
182                     const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
183     if (infoA.width() != infoB.width() || infoA.height() != infoB.height()) {
184         static constexpr float kDummyDiffs[4] = {};
185         error(-1, -1, kDummyDiffs);
186         return false;
187     }
188 
189     SkAlphaType floatAlphaType = infoA.alphaType();
190     // If one is premul and the other is unpremul we do the comparison in premul space.
191     if ((infoA.alphaType() == kPremul_SkAlphaType ||
192          infoB.alphaType() == kPremul_SkAlphaType) &&
193         (infoA.alphaType() == kUnpremul_SkAlphaType ||
194          infoB.alphaType() == kUnpremul_SkAlphaType)) {
195         floatAlphaType = kPremul_SkAlphaType;
196     }
197     sk_sp<SkColorSpace> floatCS;
198     if (SkColorSpace::Equals(infoA.colorSpace(), infoB.colorSpace())) {
199         floatCS = infoA.refColorSpace();
200     } else {
201         floatCS = SkColorSpace::MakeSRGBLinear();
202     }
203     GrPixelInfo floatInfo(GrColorType::kRGBA_F32, floatAlphaType, std::move(floatCS),
204                           infoA.width(), infoA.height());
205 
206     size_t floatBpp = GrColorTypeBytesPerPixel(GrColorType::kRGBA_F32);
207     size_t floatRowBytes = floatBpp * infoA.width();
208     std::unique_ptr<char[]> floatA(new char[floatRowBytes * infoA.height()]);
209     std::unique_ptr<char[]> floatB(new char[floatRowBytes * infoA.height()]);
210     SkAssertResult(GrConvertPixels(floatInfo, floatA.get(), floatRowBytes, infoA, a, rowBytesA));
211     SkAssertResult(GrConvertPixels(floatInfo, floatB.get(), floatRowBytes, infoB, b, rowBytesB));
212 
213     auto at = [floatBpp, floatRowBytes](const char* floatBuffer, int x, int y) {
214         return reinterpret_cast<const float*>(floatBuffer + y * floatRowBytes + x * floatBpp);
215     };
216     for (int y = 0; y < infoA.height(); ++y) {
217         for (int x = 0; x < infoA.width(); ++x) {
218             const float* rgbaA = at(floatA.get(), x, y);
219             const float* rgbaB = at(floatB.get(), x, y);
220             float diffs[4];
221             bool bad = false;
222             for (int i = 0; i < 4; ++i) {
223                 diffs[i] = rgbaB[i] - rgbaA[i];
224                 if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
225                     bad = true;
226                 }
227             }
228             if (bad) {
229                 error(x, y, diffs);
230                 return false;
231             }
232         }
233     }
234     return true;
235 }
236 
compare_pixels(const SkPixmap & a,const SkPixmap & b,const float tolRGBA[4],std::function<ComparePixmapsErrorReporter> & error)237 bool compare_pixels(const SkPixmap& a, const SkPixmap& b, const float tolRGBA[4],
238                     std::function<ComparePixmapsErrorReporter>& error) {
239     return compare_pixels(a.info(), static_cast<const char*>(a.addr()), a.rowBytes(),
240                           b.info(), static_cast<const char*>(b.addr()), b.rowBytes(),
241                           tolRGBA, error);
242 }
243 
244 #include "src/utils/SkCharToGlyphCache.h"
245 
hash_to_glyph(uint32_t value)246 static SkGlyphID hash_to_glyph(uint32_t value) {
247     return SkToU16(((value >> 16) ^ value) & 0xFFFF);
248 }
249 
250 namespace {
251 class UnicharGen {
252     SkUnichar fU;
253     const int fStep;
254 public:
UnicharGen(int step)255     UnicharGen(int step) : fU(0), fStep(step) {}
256 
next()257     SkUnichar next() {
258         fU += fStep;
259         return fU;
260     }
261 };
262 }
263 
DEF_TEST(chartoglyph_cache,reporter)264 DEF_TEST(chartoglyph_cache, reporter) {
265     SkCharToGlyphCache cache;
266     const int step = 3;
267 
268     UnicharGen gen(step);
269     for (int i = 0; i < 500; ++i) {
270         SkUnichar c = gen.next();
271         SkGlyphID glyph = hash_to_glyph(c);
272 
273         int index = cache.findGlyphIndex(c);
274         if (index >= 0) {
275             index = cache.findGlyphIndex(c);
276         }
277         REPORTER_ASSERT(reporter, index < 0);
278         cache.insertCharAndGlyph(~index, c, glyph);
279 
280         UnicharGen gen2(step);
281         for (int j = 0; j <= i; ++j) {
282             c = gen2.next();
283             glyph = hash_to_glyph(c);
284             index = cache.findGlyphIndex(c);
285             if ((unsigned)index != glyph) {
286                 index = cache.findGlyphIndex(c);
287             }
288             REPORTER_ASSERT(reporter, (unsigned)index == glyph);
289         }
290     }
291 }
292