| /* |
| * 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 <atomic> |
| |
| class Barrier { |
| public: |
| Barrier(int threadCount) : fThreadCount(threadCount) { } |
| void waitForAll() { |
| fThreadCount -= 1; |
| while (fThreadCount > 0) { } |
| } |
| |
| private: |
| std::atomic<int> fThreadCount; |
| }; |
| |
| DEF_TEST(SkScalerCacheMultiThread, Reporter) { |
| sk_sp<SkTypeface> 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<int>(' '), 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<SkScalerContext> 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); |
| } |
| } |