/* * Copyright 2020 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkFont.h" #include "include/core/SkTypeface.h" #include "src/core/SkScalerCache.h" #include "src/core/SkStrikeSpec.h" #include "src/core/SkTaskGroup.h" #include "tests/Test.h" #include "tools/ToolUtils.h" #include class Barrier { public: Barrier(int threadCount) : fThreadCount(threadCount) { } void waitForAll() { fThreadCount -= 1; while (fThreadCount > 0) { } } private: std::atomic fThreadCount; }; DEF_TEST(SkScalerCacheMultiThread, Reporter) { sk_sp typeface = ToolUtils::create_portable_typeface("serif", SkFontStyle::Italic()); static constexpr int kThreadCount = 4; Barrier barrier{kThreadCount}; SkFont font; font.setEdging(SkFont::Edging::kAntiAlias); font.setSubpixel(true); font.setTypeface(typeface); SkGlyphID glyphs['z']; SkPoint pos['z']; for (int c = ' '; c < 'z'; c++) { glyphs[c] = font.unicharToGlyph(c); pos[c] = {30.0f * c + 30, 30.0f}; } constexpr size_t glyphCount = 'z' - ' '; auto data = SkMakeZip(glyphs, pos).subspan(SkTo(' '), glyphCount); SkPaint defaultPaint; SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask( font, defaultPaint, SkSurfaceProps(0, kUnknown_SkPixelGeometry), SkScalerContextFlags::kNone, SkMatrix::I()); // Make our own executor so the --threads parameter doesn't mess things up. auto executor = SkExecutor::MakeFIFOThreadPool(kThreadCount); for (int tries = 0; tries < 100; tries++) { SkScalerContextEffects effects; std::unique_ptr ctx{ typeface->createScalerContext(effects, &strikeSpec.descriptor())}; SkScalerCache scalerCache{strikeSpec.descriptor(), std::move(ctx)}; auto perThread = [&](int threadIndex) { barrier.waitForAll(); auto local = data.subspan(threadIndex * 2, data.size() - kThreadCount * 2); for (int i = 0; i < 100; i++) { SkDrawableGlyphBuffer drawable; SkSourceGlyphBuffer rejects; drawable.ensureSize(glyphCount); rejects.setSource(local); drawable.startBitmapDevice(rejects.source(), {0, 0}, SkMatrix::I(), scalerCache.roundingSpec()); scalerCache.prepareForMaskDrawing(&drawable, &rejects); rejects.flipRejectsToSource(); drawable.reset(); } }; SkTaskGroup(*executor).batch(kThreadCount, perThread); } }