Flutter Engine
The Flutter Engine
Classes | Functions | Variables
TextBlobCacheTest.cpp File Reference
#include "include/core/SkAlphaType.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkBlendMode.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkColorType.h"
#include "include/core/SkDataTable.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkFontTypes.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkStream.h"
#include "include/core/SkString.h"
#include "include/core/SkSurface.h"
#include "include/core/SkSurfaceProps.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/encode/SkPngEncoder.h"
#include "include/gpu/GpuTypes.h"
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
#include "include/private/base/SkTArray.h"
#include "include/private/base/SkTemplates.h"
#include "include/private/base/SkTo.h"
#include "src/base/SkSpinlock.h"
#include "src/gpu/ganesh/GrDirectContextPriv.h"
#include "src/gpu/ganesh/text/GrAtlasManager.h"
#include "src/text/gpu/TextBlobRedrawCoordinator.h"
#include "tests/CtsEnforcement.h"
#include "tests/Test.h"
#include "tools/fonts/FontToolUtils.h"
#include "tools/fonts/RandomScalerContext.h"
#include "tools/gpu/ganesh/GrAtlasTools.h"
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <string>

Go to the source code of this file.

Classes

class  GrTextBlobTestingPeer
 

Functions

static void draw (SkCanvas *canvas, int redraw, const TArray< sk_sp< SkTextBlob > > &blobs)
 
static void setup_always_evict_atlas (GrDirectContext *dContext)
 
static void text_blob_cache_inner (skiatest::Reporter *reporter, GrDirectContext *dContext, int maxTotalText, int maxGlyphID, int maxFamilies, bool normal, bool stressTest)
 
 DEF_GANESH_TEST_FOR_MOCK_CONTEXT (TextBlobCache, reporter, ctxInfo)
 
 DEF_GANESH_TEST_FOR_MOCK_CONTEXT (TextBlobStressCache, reporter, ctxInfo)
 
 DEF_GANESH_TEST_FOR_MOCK_CONTEXT (TextBlobAbnormal, reporter, ctxInfo)
 
 DEF_GANESH_TEST_FOR_MOCK_CONTEXT (TextBlobStressAbnormal, reporter, ctxInfo)
 
static SkBitmap draw_blob (SkTextBlob *blob, SkSurface *surface, SkPoint offset)
 
static bool compare_bitmaps (const SkBitmap &expected, const SkBitmap &actual)
 
static sk_sp< SkTextBlobmake_blob ()
 
void write_png (const std::string &filename, const SkBitmap &bitmap)
 
 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS (TextBlobJaggedGlyph, reporter, ctxInfo, CtsEnforcement::kApiLevel_T)
 
 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS (TextBlobSmoothScroll, reporter, ctxInfo, CtsEnforcement::kApiLevel_T)
 

Variables

static const int kWidth = 1024
 
static const int kHeight = 768
 
static const int kScreenDim = 160
 
static const bool kDumpPngs = true
 

Function Documentation

◆ compare_bitmaps()

static bool compare_bitmaps ( const SkBitmap expected,
const SkBitmap actual 
)
static

Definition at line 234 of file TextBlobCacheTest.cpp.

234 {
235 SkASSERT(expected.width() == actual.width());
236 SkASSERT(expected.height() == actual.height());
237 for (int i = 0; i < expected.width(); ++i) {
238 for (int j = 0; j < expected.height(); ++j) {
239 SkColor expectedColor = expected.getColor(i, j);
240 SkColor actualColor = actual.getColor(i, j);
241 if (expectedColor != actualColor) {
242 return false;
243 }
244 }
245 }
246 return true;
247}
#define SkASSERT(cond)
Definition: SkAssert.h:116
uint32_t SkColor
Definition: SkColor.h:37
SkColor getColor(int x, int y) const
Definition: SkBitmap.h:874
int width() const
Definition: SkBitmap.h:149
int height() const
Definition: SkBitmap.h:158

◆ DEF_GANESH_TEST_FOR_MOCK_CONTEXT() [1/4]

DEF_GANESH_TEST_FOR_MOCK_CONTEXT ( TextBlobAbnormal  ,
reporter  ,
ctxInfo   
)

Definition at line 208 of file TextBlobCacheTest.cpp.

208 {
209 text_blob_cache_inner(reporter, ctxInfo.directContext(), 256, 256, 10, false, false);
210}
reporter
Definition: FontMgrTest.cpp:39
static void text_blob_cache_inner(skiatest::Reporter *reporter, GrDirectContext *dContext, int maxTotalText, int maxGlyphID, int maxFamilies, bool normal, bool stressTest)

◆ DEF_GANESH_TEST_FOR_MOCK_CONTEXT() [2/4]

DEF_GANESH_TEST_FOR_MOCK_CONTEXT ( TextBlobCache  ,
reporter  ,
ctxInfo   
)

Definition at line 200 of file TextBlobCacheTest.cpp.

200 {
201 text_blob_cache_inner(reporter, ctxInfo.directContext(), 1024, 256, 30, true, false);
202}

◆ DEF_GANESH_TEST_FOR_MOCK_CONTEXT() [3/4]

DEF_GANESH_TEST_FOR_MOCK_CONTEXT ( TextBlobStressAbnormal  ,
reporter  ,
ctxInfo   
)

Definition at line 212 of file TextBlobCacheTest.cpp.

212 {
213 text_blob_cache_inner(reporter, ctxInfo.directContext(), 256, 256, 10, false, true);
214}

◆ DEF_GANESH_TEST_FOR_MOCK_CONTEXT() [4/4]

DEF_GANESH_TEST_FOR_MOCK_CONTEXT ( TextBlobStressCache  ,
reporter  ,
ctxInfo   
)

Definition at line 204 of file TextBlobCacheTest.cpp.

204 {
205 text_blob_cache_inner(reporter, ctxInfo.directContext(), 256, 256, 10, true, true);
206}

◆ DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS() [1/2]

DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS ( TextBlobJaggedGlyph  ,
reporter  ,
ctxInfo  ,
CtsEnforcement::kApiLevel_T   
)

Definition at line 327 of file TextBlobCacheTest.cpp.

330 {
331 auto direct = ctxInfo.directContext();
332 const SkImageInfo info =
335
336 auto blob = make_blob();
337
338 for (int y = 40; y < kScreenDim - 40; y++) {
339 SkBitmap base = draw_blob(blob.get(), surface.get(), {40, y + 0.0f});
340 SkBitmap half = draw_blob(blob.get(), surface.get(), {40, y + 0.5f});
341 SkBitmap unit = draw_blob(blob.get(), surface.get(), {40, y + 1.0f});
342 bool isOk = compare_bitmaps(base, half) || compare_bitmaps(unit, half);
344 if (!isOk) {
345 if (kDumpPngs) {
346 {
347 std::string filename = "bad/half-y" + std::to_string(y) + ".png";
348 write_png(filename, half);
349 }
350 {
351 std::string filename = "good/half-y" + std::to_string(y) + ".png";
352 write_png(filename, base);
353 }
354 }
355 break;
356 }
357 }
358
359 // Testing the x direction across all platforms does not workout, because letter spacing can
360 // change based on non-integer advance widths, but this has been useful for diagnosing problems.
361#if 0
362 blob = make_blob();
363 for (int x = 40; x < kScreenDim - 40; x++) {
364 SkBitmap base = draw_blob(blob.get(), surface.get(), {x + 0.0f, 40});
365 SkBitmap half = draw_blob(blob.get(), surface.get(), {x + 0.5f, 40});
366 SkBitmap unit = draw_blob(blob.get(), surface.get(), {x + 1.0f, 40});
367 bool isOk = compare_bitmaps(base, half) || compare_bitmaps(unit, half);
369 if (!isOk) {
370 if (kDumpPngs) {
371 {
372 std::string filename = "bad/half-x" + std::to_string(x) + ".png";
373 write_png(filename, half);
374 }
375 {
376 std::string filename = "good/half-x" + std::to_string(x) + ".png";
377 write_png(filename, base);
378 }
379 }
380 break;
381 }
382 }
383#endif
384}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
static sk_sp< SkTextBlob > make_blob()
static bool compare_bitmaps(const SkBitmap &expected, const SkBitmap &actual)
static const int kScreenDim
static const bool kDumpPngs
static SkBitmap draw_blob(SkTextBlob *blob, SkSurface *surface, SkPoint offset)
void write_png(const std::string &filename, const SkBitmap &bitmap)
VkSurfaceKHR surface
Definition: main.cc:49
double y
double x
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
static SkString to_string(int n)
Definition: nanobench.cpp:119
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)

◆ DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS() [2/2]

DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS ( TextBlobSmoothScroll  ,
reporter  ,
ctxInfo  ,
CtsEnforcement::kApiLevel_T   
)

Definition at line 386 of file TextBlobCacheTest.cpp.

389 {
390 auto direct = ctxInfo.directContext();
391 const SkImageInfo info =
394
395 auto movingBlob = make_blob();
396
397 for (SkScalar y = 40; y < 50; y += 1.0/8.0) {
398 auto expectedBlob = make_blob();
399 auto expectedBitMap = draw_blob(expectedBlob.get(), surface.get(), {40, y});
400 auto movingBitmap = draw_blob(movingBlob.get(), surface.get(), {40, y});
401 bool isOk = compare_bitmaps(expectedBitMap, movingBitmap);
403 if (!isOk) {
404 if (kDumpPngs) {
405 {
406 std::string filename = "bad/scroll-y" + std::to_string(y) + ".png";
407 write_png(filename, movingBitmap);
408 }
409 {
410 std::string filename = "good/scroll-y" + std::to_string(y) + ".png";
411 write_png(filename, expectedBitMap);
412 }
413 }
414 break;
415 }
416 }
417}
float SkScalar
Definition: extension.cpp:12

◆ draw()

static void draw ( SkCanvas canvas,
int  redraw,
const TArray< sk_sp< SkTextBlob > > &  blobs 
)
static

Definition at line 62 of file TextBlobCacheTest.cpp.

62 {
63 int yOffset = 0;
64 for (int r = 0; r < redraw; r++) {
65 for (int i = 0; i < blobs.size(); i++) {
66 const auto& blob = blobs[i];
67 const SkRect& bounds = blob->bounds();
68 yOffset += SkScalarCeilToInt(bounds.height());
70 canvas->drawTextBlob(blob, 0, SkIntToScalar(yOffset), paint);
71 }
72 }
73}
#define SkScalarCeilToInt(x)
Definition: SkScalar.h:36
#define SkIntToScalar(x)
Definition: SkScalar.h:57
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2484
int size() const
Definition: SkTArray.h:421
const Paint & paint
Definition: color_source.cc:38
Optional< SkRect > bounds
Definition: SkRecords.h:189

◆ draw_blob()

static SkBitmap draw_blob ( SkTextBlob blob,
SkSurface surface,
SkPoint  offset 
)
static

Definition at line 218 of file TextBlobCacheTest.cpp.

218 {
219
221
222 SkCanvas* canvas = surface->getCanvas();
223 canvas->save();
225 canvas->translate(offset.fX, offset.fY);
226 canvas->drawTextBlob(blob, 0, 0, paint);
228 bitmap.allocN32Pixels(kScreenDim, kScreenDim);
229 surface->readPixels(bitmap, 0, 0);
230 canvas->restore();
231 return bitmap;
232}
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
void drawColor(SkColor color, SkBlendMode mode=SkBlendMode::kSrcOver)
Definition: SkCanvas.h:1182
int save()
Definition: SkCanvas.cpp:447
Definition: bitmap.py:1
SeparatedVector2 offset

◆ make_blob()

static sk_sp< SkTextBlob > make_blob ( )
static

Definition at line 249 of file TextBlobCacheTest.cpp.

249 {
250 auto tf = ToolUtils::CreateTestTypeface("Roboto2-Regular", SkFontStyle());
251 SkFont font;
252 font.setTypeface(tf);
253 font.setSubpixel(false);
254 font.setEdging(SkFont::Edging::kAlias);
255 font.setSize(24);
256
257 static char text[] = "HekpqB";
258 static const int maxGlyphLen = sizeof(text) * 4;
259 SkGlyphID glyphs[maxGlyphLen];
260 int glyphCount =
261 font.textToGlyphs(text, sizeof(text), SkTextEncoding::kUTF8, glyphs, maxGlyphLen);
262
264 const auto& runBuffer = builder.allocRun(font, glyphCount, 0, 0);
265 for (int i = 0; i < glyphCount; i++) {
266 runBuffer.glyphs[i] = glyphs[i];
267 }
268 return builder.make();
269}
uint16_t glyphs[5]
Definition: FontMgrTest.cpp:46
@ kUTF8
uses bytes to represent UTF-8 or ASCII
uint16_t SkGlyphID
Definition: SkTypes.h:179
Definition: SkFont.h:35
@ kAlias
no transparent pixels on glyph edges
std::u16string text
sk_sp< SkTypeface > CreateTestTypeface(const char *name, SkFontStyle style)
font
Font Metadata and Metrics.

◆ setup_always_evict_atlas()

static void setup_always_evict_atlas ( GrDirectContext dContext)
static

Definition at line 78 of file TextBlobCacheTest.cpp.

78 {
80}
static void SetAtlasDimensionsToMinimum(GrAtlasManager *)
GrAtlasManager * getAtlasManager()
GrDirectContextPriv priv()

◆ text_blob_cache_inner()

static void text_blob_cache_inner ( skiatest::Reporter reporter,
GrDirectContext dContext,
int  maxTotalText,
int  maxGlyphID,
int  maxFamilies,
bool  normal,
bool  stressTest 
)
static

Definition at line 92 of file TextBlobCacheTest.cpp.

94 {
95 // setup surface
96 uint32_t flags = 0;
98
99 // configure our context for maximum stressing of cache and atlas
100 if (stressTest) {
101 setup_always_evict_atlas(dContext);
103 }
104
107 auto surface(SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info, 0, &props));
109 if (!surface) {
110 return;
111 }
112
113 SkCanvas* canvas = surface->getCanvas();
114
116
117 int count = std::min(fm->countFamilies(), maxFamilies);
118
119 // make a ton of text
120 AutoTArray<uint16_t> text(maxTotalText);
121 for (int i = 0; i < maxTotalText; i++) {
122 text[i] = i % maxGlyphID;
123 }
124
125 // generate textblobs
127 for (int i = 0; i < count; i++) {
128 SkFont font;
129 font.setSize(48); // draw big glyphs to really stress the atlas
130
131 SkString familyName;
132 fm->getFamilyName(i, &familyName);
133 sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
134 for (int j = 0; j < set->count(); ++j) {
135 SkFontStyle fs;
136 set->getStyle(j, &fs, nullptr);
137
138 // We use a typeface which randomy returns unexpected mask formats to fuzz
139 sk_sp<SkTypeface> orig(set->createTypeface(j));
140 if (normal) {
141 font.setTypeface(orig);
142 } else {
143 font.setTypeface(sk_make_sp<SkRandomTypeface>(orig, SkPaint(), true));
144 }
145
147 for (int aa = 0; aa < 2; aa++) {
148 for (int subpixel = 0; subpixel < 2; subpixel++) {
149 for (int lcd = 0; lcd < 2; lcd++) {
150 font.setEdging(SkFont::Edging::kAlias);
151 if (aa) {
153 if (lcd) {
155 }
156 }
157 font.setSubpixel(SkToBool(subpixel));
158 if (!SkToBool(lcd)) {
159 font.setSize(160);
160 }
162 maxTotalText,
163 0, 0,
164 nullptr);
165 memcpy(run.glyphs, text.get(), maxTotalText * sizeof(uint16_t));
166 }
167 }
168 }
169 blobs.emplace_back(builder.make());
170 }
171 }
172
173 // create surface where LCD is impossible
176 auto surfaceNoLCD(canvas->makeSurface(info, &propsNoLCD));
178 if (!surface) {
179 return;
180 }
181
182 SkCanvas* canvasNoLCD = surfaceNoLCD->getCanvas();
183
184 // test redraw
185 draw(canvas, 2, blobs);
186 draw(canvasNoLCD, 2, blobs);
187
188 // test draw after free
189 dContext->freeGpuResources();
190 draw(canvas, 1, blobs);
191
192 dContext->freeGpuResources();
193 draw(canvasNoLCD, 1, blobs);
194
195 // test draw after abandon
196 dContext->abandonContext();
197 draw(canvas, 1, blobs);
198}
int count
Definition: FontMgrTest.cpp:50
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kUnknown_SkPixelGeometry
@ kRGB_H_SkPixelGeometry
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
static void draw(SkCanvas *canvas, int redraw, const TArray< sk_sp< SkTextBlob > > &blobs)
static void setup_always_evict_atlas(GrDirectContext *dContext)
static const int kHeight
static const int kWidth
void abandonContext() override
sktext::gpu::TextBlobRedrawCoordinator * getTextBlobCache()
static void SetBudget(sktext::gpu::TextBlobRedrawCoordinator *cache, size_t budget)
sk_sp< SkSurface > makeSurface(const SkImageInfo &info, const SkSurfaceProps *props=nullptr)
Definition: SkCanvas.cpp:1195
@ kAntiAlias
may have transparent pixels on glyph edges
@ kSubpixelAntiAlias
glyph positioned in pixel using transparency
T & emplace_back(Args &&... args)
Definition: SkTArray.h:248
FlutterSemanticsFlag flags
static float min(float r, float g, float b)
Definition: hsl.cpp:48
sk_sp< SkFontMgr > TestFontMgr()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
Definition: run.py:1

◆ write_png()

void write_png ( const std::string &  filename,
const SkBitmap bitmap 
)

Definition at line 321 of file TextBlobCacheTest.cpp.

321 {
322 SkFILEWStream w{filename.c_str()};
324 w.fsync();
325}
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SkScalar w

Variable Documentation

◆ kDumpPngs

const bool kDumpPngs = true
static

Definition at line 317 of file TextBlobCacheTest.cpp.

◆ kHeight

const int kHeight = 768
static

Definition at line 76 of file TextBlobCacheTest.cpp.

◆ kScreenDim

const int kScreenDim = 160
static

Definition at line 216 of file TextBlobCacheTest.cpp.

◆ kWidth

const int kWidth = 1024
static

Definition at line 75 of file TextBlobCacheTest.cpp.