1/* 2 * Copyright 2020 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 "include/core/SkFont.h" 9#include "include/core/SkTypeface.h" 10#include "src/core/SkScalerCache.h" 11#include "src/core/SkStrikeSpec.h" 12#include "src/core/SkTaskGroup.h" 13#include "tests/Test.h" 14#include "tools/ToolUtils.h" 15 16#include <atomic> 17 18class Barrier { 19public: 20 Barrier(int threadCount) : fThreadCount(threadCount) { } 21 void waitForAll() { 22 fThreadCount -= 1; 23 while (fThreadCount > 0) { } 24 } 25 26private: 27 std::atomic<int> fThreadCount; 28}; 29 30DEF_TEST(SkScalerCacheMultiThread, Reporter) { 31 sk_sp<SkTypeface> typeface = 32 ToolUtils::create_portable_typeface("serif", SkFontStyle::Italic()); 33 static constexpr int kThreadCount = 4; 34 35 Barrier barrier{kThreadCount}; 36 37 SkFont font; 38 font.setEdging(SkFont::Edging::kAntiAlias); 39 font.setSubpixel(true); 40 font.setTypeface(typeface); 41 42 SkGlyphID glyphs['z']; 43 SkPoint pos['z']; 44 for (int c = ' '; c < 'z'; c++) { 45 glyphs[c] = font.unicharToGlyph(c); 46 pos[c] = {30.0f * c + 30, 30.0f}; 47 } 48 constexpr size_t glyphCount = 'z' - ' '; 49 auto data = SkMakeZip(glyphs, pos).subspan(SkTo<int>(' '), glyphCount); 50 51 SkPaint defaultPaint; 52 SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask( 53 font, defaultPaint, SkSurfaceProps(0, kUnknown_SkPixelGeometry), 54 SkScalerContextFlags::kNone, SkMatrix::I()); 55 56 // Make our own executor so the --threads parameter doesn't mess things up. 57 auto executor = SkExecutor::MakeFIFOThreadPool(kThreadCount); 58 for (int tries = 0; tries < 100; tries++) { 59 SkScalerCache scalerCache{strikeSpec.createScalerContext()}; 60 61 auto perThread = [&](int threadIndex) { 62 barrier.waitForAll(); 63 64 auto local = data.subspan(threadIndex * 2, data.size() - kThreadCount * 2); 65 for (int i = 0; i < 100; i++) { 66 SkDrawableGlyphBuffer drawable; 67 SkSourceGlyphBuffer rejects; 68 69 drawable.ensureSize(glyphCount); 70 rejects.setSource(local); 71 72 drawable.startBitmapDevice(rejects.source(), {0, 0}, SkMatrix::I(), 73 scalerCache.roundingSpec()); 74 scalerCache.prepareForMaskDrawing(&drawable, &rejects); 75 rejects.flipRejectsToSource(); 76 drawable.reset(); 77 } 78 }; 79 80 SkTaskGroup(*executor).batch(kThreadCount, perThread); 81 } 82} 83