blob: 2e6120a8161132482d716da95ecf5f2a707fe087 [file] [log] [blame]
Robert Phillips3500b772017-01-27 10:11:42 -05001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tests/TestUtils.h"
Robert Phillips3500b772017-01-27 10:11:42 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/encode/SkPngEncoder.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/utils/SkBase64.h"
Robert Phillipsee5fd132019-05-07 13:29:22 -040012#include "src/core/SkUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrContextPriv.h"
Greg Daniel46cfbc62019-06-07 11:43:30 -040014#include "src/gpu/GrDrawingManager.h"
Robert Phillipsee5fd132019-05-07 13:29:22 -040015#include "src/gpu/GrGpu.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040016#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/GrSurfaceContext.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040018#include "src/gpu/GrSurfaceProxy.h"
Greg Daniel46cfbc62019-06-07 11:43:30 -040019#include "src/gpu/GrTextureContext.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040020#include "src/gpu/GrTextureProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/SkGr.h"
Robert Phillips3500b772017-01-27 10:11:42 -050022
Robert Phillips26c90e02017-03-14 14:39:29 -040023void test_read_pixels(skiatest::Reporter* reporter,
Robert Phillips3500b772017-01-27 10:11:42 -050024 GrSurfaceContext* srcContext, uint32_t expectedPixelValues[],
25 const char* testName) {
26 int pixelCnt = srcContext->width() * srcContext->height();
27 SkAutoTMalloc<uint32_t> pixels(pixelCnt);
28 memset(pixels.get(), 0, sizeof(uint32_t)*pixelCnt);
29
30 SkImageInfo ii = SkImageInfo::Make(srcContext->width(), srcContext->height(),
31 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Brian Salomon1d435302019-07-01 13:05:28 -040032 bool read = srcContext->readPixels(ii, pixels.get(), 0, {0, 0});
Robert Phillips3500b772017-01-27 10:11:42 -050033 if (!read) {
34 ERRORF(reporter, "%s: Error reading from texture.", testName);
35 }
36
37 for (int i = 0; i < pixelCnt; ++i) {
38 if (pixels.get()[i] != expectedPixelValues[i]) {
39 ERRORF(reporter, "%s: Error, pixel value %d should be 0x%08x, got 0x%08x.",
40 testName, i, expectedPixelValues[i], pixels.get()[i]);
41 break;
42 }
43 }
44}
45
Robert Phillips26c90e02017-03-14 14:39:29 -040046void test_write_pixels(skiatest::Reporter* reporter,
Robert Phillips3500b772017-01-27 10:11:42 -050047 GrSurfaceContext* dstContext, bool expectedToWork,
48 const char* testName) {
49 int pixelCnt = dstContext->width() * dstContext->height();
50 SkAutoTMalloc<uint32_t> pixels(pixelCnt);
51 for (int y = 0; y < dstContext->width(); ++y) {
52 for (int x = 0; x < dstContext->height(); ++x) {
53 pixels.get()[y * dstContext->width() + x] =
Brian Osman4408b1c2018-10-29 14:11:04 -040054 SkColorToPremulGrColor(SkColorSetARGB(2*y, x, y, x + y));
Robert Phillips3500b772017-01-27 10:11:42 -050055 }
56 }
57
58 SkImageInfo ii = SkImageInfo::Make(dstContext->width(), dstContext->height(),
59 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Brian Salomon1d435302019-07-01 13:05:28 -040060 bool write = dstContext->writePixels(ii, pixels.get(), 0, {0, 0});
Robert Phillips3500b772017-01-27 10:11:42 -050061 if (!write) {
62 if (expectedToWork) {
63 ERRORF(reporter, "%s: Error writing to texture.", testName);
64 }
65 return;
66 }
67
68 if (write && !expectedToWork) {
69 ERRORF(reporter, "%s: writePixels succeeded when it wasn't supposed to.", testName);
70 return;
71 }
72
Robert Phillips26c90e02017-03-14 14:39:29 -040073 test_read_pixels(reporter, dstContext, pixels.get(), testName);
Robert Phillips3500b772017-01-27 10:11:42 -050074}
75
Brian Salomond6287472019-06-24 15:50:07 -040076void test_copy_from_surface(skiatest::Reporter* reporter, GrContext* context, GrSurfaceProxy* proxy,
77 GrColorType colorType, uint32_t expectedPixelValues[],
Greg Daniel46cfbc62019-06-07 11:43:30 -040078 const char* testName) {
Brian Salomond6287472019-06-24 15:50:07 -040079 sk_sp<GrTextureProxy> dstProxy = GrSurfaceProxy::Copy(context, proxy, GrMipMapped::kNo,
Greg Daniel46cfbc62019-06-07 11:43:30 -040080 SkBackingFit::kExact, SkBudgeted::kYes);
81 SkASSERT(dstProxy);
Robert Phillips3500b772017-01-27 10:11:42 -050082
Brian Salomonbf6b9792019-08-21 09:38:10 -040083 auto dstContext = context->priv().makeWrappedSurfaceContext(std::move(dstProxy), colorType,
84 kPremul_SkAlphaType);
85 SkASSERT(dstContext);
Robert Phillips3500b772017-01-27 10:11:42 -050086
Greg Daniel46cfbc62019-06-07 11:43:30 -040087 test_read_pixels(reporter, dstContext.get(), expectedPixelValues, testName);
Robert Phillips3500b772017-01-27 10:11:42 -050088}
Timothy Liang760dbc42018-07-17 13:28:20 -040089
90void fill_pixel_data(int width, int height, GrColor* data) {
91 for (int j = 0; j < height; ++j) {
92 for (int i = 0; i < width; ++i) {
93 unsigned int red = (unsigned int)(256.f * (i / (float)width));
94 unsigned int green = (unsigned int)(256.f * (j / (float)height));
95 data[i + j * width] = GrColorPackRGBA(red - (red >> 8), green - (green >> 8),
96 0xff, 0xff);
97 }
98 }
99}
100
Robert Phillipsee5fd132019-05-07 13:29:22 -0400101bool create_backend_texture(GrContext* context, GrBackendTexture* backendTex,
Robert Phillips4d87b2b2019-07-23 13:44:16 -0400102 const SkImageInfo& ii, const SkColor4f& color,
103 GrMipMapped mipMapped, GrRenderable renderable) {
Robert Phillips4d87b2b2019-07-23 13:44:16 -0400104 *backendTex = context->createBackendTexture(ii.width(), ii.height(), ii.colorType(),
105 color, mipMapped, renderable);
Robert Phillipscb1adb42019-06-10 15:09:34 -0400106 return backendTex->isValid();
Robert Phillipsee5fd132019-05-07 13:29:22 -0400107}
108
109void delete_backend_texture(GrContext* context, const GrBackendTexture& backendTex) {
Greg Danielb3f82dd2019-05-29 14:24:32 -0400110 GrFlushInfo flushInfo;
111 flushInfo.fFlags = kSyncCpu_GrFlushFlag;
112 context->flush(flushInfo);
Robert Phillips5c7a25b2019-05-20 08:38:07 -0400113 context->deleteBackendTexture(backendTex);
Robert Phillipsee5fd132019-05-07 13:29:22 -0400114}
115
Robert Phillipscb1adb42019-06-10 15:09:34 -0400116bool does_full_buffer_contain_correct_color(const GrColor* srcBuffer,
117 const GrColor* dstBuffer,
Timothy Liang760dbc42018-07-17 13:28:20 -0400118 int width,
119 int height) {
Robert Phillipscb1adb42019-06-10 15:09:34 -0400120 const GrColor* srcPtr = srcBuffer;
121 const GrColor* dstPtr = dstBuffer;
Timothy Liang760dbc42018-07-17 13:28:20 -0400122 for (int j = 0; j < height; ++j) {
123 for (int i = 0; i < width; ++i) {
124 if (srcPtr[i] != dstPtr[i]) {
125 return false;
126 }
127 }
128 srcPtr += width;
129 dstPtr += width;
130 }
131 return true;
132}
Michael Ludwige8e10752018-10-01 12:42:53 -0400133
134bool bitmap_to_base64_data_uri(const SkBitmap& bitmap, SkString* dst) {
135 SkPixmap pm;
136 if (!bitmap.peekPixels(&pm)) {
137 dst->set("peekPixels failed");
138 return false;
139 }
140
141 // We're going to embed this PNG in a data URI, so make it as small as possible
142 SkPngEncoder::Options options;
143 options.fFilterFlags = SkPngEncoder::FilterFlag::kAll;
144 options.fZLibLevel = 9;
145
146 SkDynamicMemoryWStream wStream;
147 if (!SkPngEncoder::Encode(&wStream, pm, options)) {
148 dst->set("SkPngEncoder::Encode failed");
149 return false;
150 }
151
152 sk_sp<SkData> pngData = wStream.detachAsData();
153 size_t len = SkBase64::Encode(pngData->data(), pngData->size(), nullptr);
154
155 // The PNG can be almost arbitrarily large. We don't want to fill our logs with enormous URLs.
156 // Infra says these can be pretty big, as long as we're only outputting them on failure.
157 static const size_t kMaxBase64Length = 1024 * 1024;
158 if (len > kMaxBase64Length) {
159 dst->printf("Encoded image too large (%u bytes)", static_cast<uint32_t>(len));
160 return false;
161 }
162
163 dst->resize(len);
164 SkBase64::Encode(pngData->data(), pngData->size(), dst->writable_str());
165 dst->prepend("data:image/png;base64,");
166 return true;
167}
Mike Reed0c607082019-04-11 17:10:17 -0400168
Robert Phillipse3b6fe42019-09-11 11:26:46 -0400169using AccessPixelFn = const float*(const char* floatBuffer, int x, int y);
170
171bool compare_pixels(int width, int height,
172 const char* floatA, std::function<AccessPixelFn>& atA,
173 const char* floatB, std::function<AccessPixelFn>& atB,
174 const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
175
176 for (int y = 0; y < height; ++y) {
177 for (int x = 0; x < width; ++x) {
178 const float* rgbaA = atA(floatA, x, y);
179 const float* rgbaB = atB(floatB, x, y);
180 float diffs[4];
181 bool bad = false;
182 for (int i = 0; i < 4; ++i) {
183 diffs[i] = rgbaB[i] - rgbaA[i];
184 if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
185 bad = true;
186 }
187 }
188 if (bad) {
189 error(x, y, diffs);
190 return false;
191 }
192 }
193 }
194 return true;
195}
196
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400197bool compare_pixels(const GrImageInfo& infoA, const char* a, size_t rowBytesA,
198 const GrImageInfo& infoB, const char* b, size_t rowBytesB,
Brian Salomon85aeccf2019-07-15 12:30:44 -0400199 const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
200 if (infoA.width() != infoB.width() || infoA.height() != infoB.height()) {
201 static constexpr float kDummyDiffs[4] = {};
202 error(-1, -1, kDummyDiffs);
203 return false;
204 }
205
206 SkAlphaType floatAlphaType = infoA.alphaType();
207 // If one is premul and the other is unpremul we do the comparison in premul space.
208 if ((infoA.alphaType() == kPremul_SkAlphaType ||
209 infoB.alphaType() == kPremul_SkAlphaType) &&
210 (infoA.alphaType() == kUnpremul_SkAlphaType ||
211 infoB.alphaType() == kUnpremul_SkAlphaType)) {
212 floatAlphaType = kPremul_SkAlphaType;
213 }
214 sk_sp<SkColorSpace> floatCS;
215 if (SkColorSpace::Equals(infoA.colorSpace(), infoB.colorSpace())) {
216 floatCS = infoA.refColorSpace();
217 } else {
218 floatCS = SkColorSpace::MakeSRGBLinear();
219 }
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400220 GrImageInfo floatInfo(GrColorType::kRGBA_F32, floatAlphaType, std::move(floatCS),
Brian Salomon85aeccf2019-07-15 12:30:44 -0400221 infoA.width(), infoA.height());
222
223 size_t floatBpp = GrColorTypeBytesPerPixel(GrColorType::kRGBA_F32);
224 size_t floatRowBytes = floatBpp * infoA.width();
225 std::unique_ptr<char[]> floatA(new char[floatRowBytes * infoA.height()]);
226 std::unique_ptr<char[]> floatB(new char[floatRowBytes * infoA.height()]);
227 SkAssertResult(GrConvertPixels(floatInfo, floatA.get(), floatRowBytes, infoA, a, rowBytesA));
228 SkAssertResult(GrConvertPixels(floatInfo, floatB.get(), floatRowBytes, infoB, b, rowBytesB));
229
Robert Phillipse3b6fe42019-09-11 11:26:46 -0400230 auto at = std::function<AccessPixelFn>(
231 [floatBpp, floatRowBytes](const char* floatBuffer, int x, int y) {
232 return reinterpret_cast<const float*>(floatBuffer + y * floatRowBytes + x * floatBpp);
233 });
234
235 return compare_pixels(infoA.width(), infoA.height(),
236 floatA.get(), at, floatB.get(), at,
237 tolRGBA, error);
Brian Salomon85aeccf2019-07-15 12:30:44 -0400238}
239
240bool compare_pixels(const SkPixmap& a, const SkPixmap& b, const float tolRGBA[4],
241 std::function<ComparePixmapsErrorReporter>& error) {
242 return compare_pixels(a.info(), static_cast<const char*>(a.addr()), a.rowBytes(),
243 b.info(), static_cast<const char*>(b.addr()), b.rowBytes(),
244 tolRGBA, error);
245}
246
Robert Phillipse3b6fe42019-09-11 11:26:46 -0400247bool check_solid_pixels(const SkColor4f& col, const SkPixmap& pixmap,
248 const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
249
250 size_t floatBpp = GrColorTypeBytesPerPixel(GrColorType::kRGBA_F32);
251
252 std::unique_ptr<char[]> floatA(new char[floatBpp]);
253 // First convert 'col' to be compatible with 'pixmap'
254 {
255 sk_sp<SkColorSpace> srcCS = SkColorSpace::MakeSRGBLinear();
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400256 GrImageInfo srcInfo(GrColorType::kRGBA_F32, kUnpremul_SkAlphaType, std::move(srcCS), 1, 1);
257 GrImageInfo dstInfo(GrColorType::kRGBA_F32, pixmap.alphaType(), pixmap.refColorSpace(), 1, 1);
Robert Phillipse3b6fe42019-09-11 11:26:46 -0400258
259 SkAssertResult(GrConvertPixels(dstInfo, floatA.get(), floatBpp, srcInfo,
260 col.vec(), floatBpp));
261 }
262
263 size_t floatRowBytes = floatBpp * pixmap.width();
264 std::unique_ptr<char[]> floatB(new char[floatRowBytes * pixmap.height()]);
265 // Then convert 'pixmap' to RGBA_F32
266 {
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400267 GrImageInfo dstInfo(GrColorType::kRGBA_F32, pixmap.alphaType(), pixmap.refColorSpace(),
Robert Phillipse3b6fe42019-09-11 11:26:46 -0400268 pixmap.width(), pixmap.height());
269
270 SkAssertResult(GrConvertPixels(dstInfo, floatB.get(), floatRowBytes, pixmap.info(),
271 pixmap.addr(), pixmap.rowBytes()));
272 }
273
274 auto atA = std::function<AccessPixelFn>(
275 [](const char* floatBuffer, int /* x */, int /* y */) {
276 return reinterpret_cast<const float*>(floatBuffer);
277 });
278
279 auto atB = std::function<AccessPixelFn>(
280 [floatBpp, floatRowBytes](const char* floatBuffer, int x, int y) {
281 return reinterpret_cast<const float*>(floatBuffer + y * floatRowBytes + x * floatBpp);
282 });
283
284 return compare_pixels(pixmap.width(), pixmap.height(), floatA.get(), atA, floatB.get(), atB,
285 tolRGBA, error);
286}
287
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500288#include "src/utils/SkCharToGlyphCache.h"
Mike Reed0c607082019-04-11 17:10:17 -0400289
290static SkGlyphID hash_to_glyph(uint32_t value) {
291 return SkToU16(((value >> 16) ^ value) & 0xFFFF);
292}
293
294namespace {
295class UnicharGen {
296 SkUnichar fU;
297 const int fStep;
298public:
299 UnicharGen(int step) : fU(0), fStep(step) {}
300
301 SkUnichar next() {
302 fU += fStep;
303 return fU;
304 }
305};
306}
307
308DEF_TEST(chartoglyph_cache, reporter) {
309 SkCharToGlyphCache cache;
310 const int step = 3;
311
312 UnicharGen gen(step);
313 for (int i = 0; i < 500; ++i) {
314 SkUnichar c = gen.next();
315 SkGlyphID glyph = hash_to_glyph(c);
316
317 int index = cache.findGlyphIndex(c);
Mike Reed194cab02019-04-15 12:07:19 -0400318 if (index >= 0) {
319 index = cache.findGlyphIndex(c);
320 }
Mike Reed0c607082019-04-11 17:10:17 -0400321 REPORTER_ASSERT(reporter, index < 0);
322 cache.insertCharAndGlyph(~index, c, glyph);
323
324 UnicharGen gen2(step);
325 for (int j = 0; j <= i; ++j) {
326 c = gen2.next();
327 glyph = hash_to_glyph(c);
328 index = cache.findGlyphIndex(c);
Mike Reed194cab02019-04-15 12:07:19 -0400329 if ((unsigned)index != glyph) {
330 index = cache.findGlyphIndex(c);
331 }
Mike Reed0c607082019-04-11 17:10:17 -0400332 REPORTER_ASSERT(reporter, (unsigned)index == glyph);
333 }
334 }
335}