Revert of Parallel cache - preliminary (patchset #23 id:440001 of https://codereview.chromium.org/1264103003/ )

Also reverts https://codereview.chromium.org/1333003002/ which was layered on top.

Reason for revert:
Appears to leak GDI handles: http://build.chromium.org/p/chromium.memory.fyi/builders/Windows%20Unit%20%28DrMemory%20full%29%20%282%29/builds/8247

~~Dr.M~~ Error #1: HANDLE LEAK: GDI handle 0x03050a84 and 3 similar handle(s) were opened but not closed:
~~Dr.M~~ # 0 system call NtGdiCreateDIBSection
~~Dr.M~~ # 1 GDI32.dll!CreateDIBSection                                                +0xdc     (0x768ead23 <GDI32.dll+0x1ad23>)
~~Dr.M~~ # 2 skia.dll!HDCOffscreen::draw                                                [third_party\skia\src\ports\skfonthost_win.cpp:499]
~~Dr.M~~ # 3 skia.dll!SkScalerContext_GDI::generateImage                                [third_party\skia\src\ports\skfonthost_win.cpp:1233]
~~Dr.M~~ # 4 skia.dll!SkScalerContext::getImage                                         [third_party\skia\src\core\skscalercontext.cpp:530]
~~Dr.M~~ # 5 skia.dll!SkGlyphCache::OnceFillInImage                                     [third_party\skia\src\core\skglyphcache.cpp:252]
~~Dr.M~~ # 6 skia.dll!sk_once_slow<>                                                    [third_party\skia\include\core\skonce.h:76]
~~Dr.M~~ # 7 skia.dll!SkGlyphCache::findImage                                           [third_party\skia\src\core\skglyphcache.cpp:260]
~~Dr.M~~ # 8 skia.dll!D1G_RectClip                                                      [third_party\skia\src\core\skdraw.cpp:1479]
~~Dr.M~~ # 9 skia.dll!SkDraw::drawPosText                                               [third_party\skia\src\core\skdraw.cpp:1838]
~~Dr.M~~ #10 skia.dll!SkBitmapDevice::drawPosText                                       [third_party\skia\src\core\skbitmapdevice.cpp:348]
~~Dr.M~~ #11 skia.dll!SkCanvas::onDrawPosText                                           [third_party\skia\src\core\skcanvas.cpp:2433]
~~Dr.M~~ #12 skia.dll!SkCanvas::drawPosText                                             [third_party\skia\src\core\skcanvas.cpp:2507]
~~Dr.M~~ #13 skia.dll!SkRecords::Draw::draw<>                                           [third_party\skia\src\core\skrecorddraw.cpp:109]
~~Dr.M~~ #14 skia.dll!SkRecord::Record::visit<>                                         [third_party\skia\src\core\skrecord.h:170]
~~Dr.M~~ #15 skia.dll!SkRecordDraw                                                      [third_party\skia\src\core\skrecorddraw.cpp:55]
~~Dr.M~~ #16 skia.dll!SkBigPicture::playback                                            [third_party\skia\src\core\skbigpicture.cpp:43]
~~Dr.M~~ #17 skia.dll!SkCanvas::onDrawPicture                                           [third_party\skia\src\core\skcanvas.cpp:2800]
~~Dr.M~~ #18 skia.dll!SkCanvas::drawPicture                                             [third_party\skia\src\core\skcanvas.cpp:2770]
~~Dr.M~~ #19 cc.dll!cc::DrawingDisplayItem::Raster                                      [cc\playback\drawing_display_item.cc:51]
~~Dr.M~~ #20 cc.dll!cc::DisplayItemList::Raster                                         [cc\playback\display_item_list.cc:107]
~~Dr.M~~ #21 cc.dll!cc::DisplayListRasterSource::RasterCommon                           [cc\playback\display_list_raster_source.cc:122]
~~Dr.M~~ #22 cc.dll!cc::DisplayListRasterSource::PlaybackToCanvas                       [cc\playback\display_list_raster_source.cc:100]
~~Dr.M~~ #23 cc.dll!cc::TileTaskWorkerPool::PlaybackToMemory                            [cc\raster\tile_task_worker_pool.cc:208]
~~Dr.M~~ #24 cc.dll!cc::OneCopyTileTaskWorkerPool::PlaybackAndCopyOnWorkerThread        [cc\raster\one_copy_tile_task_worker_pool.cc:413]
~~Dr.M~~ #25 cc.dll!cc::`anonymous namespace'::RasterBufferImpl::Playback               [cc\raster\one_copy_tile_task_worker_pool.cc:53]
~~Dr.M~~ #26 cc.dll!cc::`anonymous namespace'::RasterTaskImpl::Raster                   [cc\tiles\tile_manager.cc:131]
~~Dr.M~~ #27 cc.dll!cc::`anonymous namespace'::RasterTaskImpl::RunOnWorkerThread        [cc\tiles\tile_manager.cc:90]
~~Dr.M~~ #28 cc.dll!cc::TaskGraphRunner::RunTaskWithLockAcquired                        [cc\raster\task_graph_runner.cc:418]
~~Dr.M~~ #29 cc.dll!cc::TaskGraphRunner::Run                                            [cc\raster\task_graph_runner.cc:361]
~~Dr.M~~ #30 base.dll!base::SimpleThread::ThreadMain                                    [base\threading\simple_thread.cc:66]
~~Dr.M~~ #31 base.dll!base::`anonymous namespace'::ThreadFunc                           [base\threading\platform_thread_win.cc:82]
~~Dr.M~~ #32 KERNEL32.dll!BaseThreadInitThunk                                          +0x11     (0x7570337a <KERNEL32.dll+0x1337a>)
~~Dr.M~~ Note: @0:15:51.087 in thread 196
~~Dr.M~~ Note: handles created with the same callstack are closed here:
~~Dr.M~~ Note: # 0 system call NtGdiDeleteObjectApp
~~Dr.M~~ Note: # 1 GDI32.dll!DeleteObject                                                    +0x149    (0x768e57d3 <GDI32.dll+0x157d3>)
~~Dr.M~~ Note: # 2 skia.dll!HDCOffscreen::draw                                                [third_party\skia\src\ports\skfonthost_win.cpp:471]
~~Dr.M~~ Note: # 3 skia.dll!SkScalerContext_GDI::generateImage                                [third_party\skia\src\ports\skfonthost_win.cpp:1233]
~~Dr.M~~ Note: # 4 skia.dll!SkScalerContext::getImage                                         [third_party\skia\src\core\skscalercontext.cpp:530]
~~Dr.M~~ Note: # 5 skia.dll!SkGlyphCache::OnceFillInImage                                     [third_party\skia\src\core\skglyphcache.cpp:252]
~~Dr.M~~ Note: # 6 skia.dll!sk_once_slow<>                                                    [third_party\skia\include\core\skonce.h:76]
~~Dr.M~~ Note: # 7 skia.dll!SkGlyphCache::findImage                                           [third_party\skia\src\core\skglyphcache.cpp:260]
~~Dr.M~~ Note: # 8 skia.dll!D1G_RectClip                                                      [third_party\skia\src\core\skdraw.cpp:1479]
~~Dr.M~~ Note: # 9 skia.dll!SkDraw::drawPosText                                               [third_party\skia\src\core\skdraw.cpp:1838]
~~Dr.M~~ Note: #10 skia.dll!SkBitmapDevice::drawPosText                                       [third_party\skia\src\core\skbitmapdevice.cpp:348]
~~Dr.M~~ Note: #11 skia.dll!SkCanvas::onDrawPosText                                           [third_party\skia\src\core\skcanvas.cpp:2433]
~~Dr.M~~ Note: #12 skia.dll!SkCanvas::drawPosText                                             [third_party\skia\src\core\skcanvas.cpp:2507]
~~Dr.M~~ Note: #13 skia.dll!SkRecords::Draw::draw<>                                           [third_party\skia\src\core\skrecorddraw.cpp:109]
~~Dr.M~~ Note: #14 skia.dll!SkRecord::Record::visit<>                                         [third_party\skia\src\core\skrecord.h:170]
~~Dr.M~~ Note: #15 skia.dll!SkRecordDraw                                                      [third_party\skia\src\core\skrecorddraw.cpp:55]
~~Dr.M~~ Note: #16 skia.dll!SkBigPicture::playback                                            [third_party\skia\src\core\skbigpicture.cpp:43]
~~Dr.M~~ Note: #17 skia.dll!SkCanvas::onDrawPicture                                           [third_party\skia\src\core\skcanvas.cpp:2800]
~~Dr.M~~ Note: #18 skia.dll!SkCanvas::drawPicture                                             [third_party\skia\src\core\skcanvas.cpp:2770]
~~Dr.M~~ Note: #19 cc.dll!cc::DrawingDisplayItem::Raster                                      [cc\playback\drawing_display_item.cc:51]
~~Dr.M~~ Note: #20 cc.dll!cc::DisplayItemList::Raster                                         [cc\playback\display_item_list.cc:107]
~~Dr.M~~ Note: #21 cc.dll!cc::DisplayListRasterSource::RasterCommon                           [cc\playback\display_list_raster_source.cc:122]
~~Dr.M~~ Note: #22 cc.dll!cc::DisplayListRasterSource::PlaybackToCanvas                       [cc\playback\display_list_raster_source.cc:100]
~~Dr.M~~ Note: #23 cc.dll!cc::TileTaskWorkerPool::PlaybackToMemory                            [cc\raster\tile_task_worker_pool.cc:208]
~~Dr.M~~ Note: #24 cc.dll!cc::OneCopyTileTaskWorkerPool::PlaybackAndCopyOnWorkerThread        [cc\raster\one_copy_tile_task_worker_pool.cc:413]
~~Dr.M~~ Note: #25 cc.dll!cc::`anonymous namespace'::RasterBufferImpl::Playback               [cc\raster\one_copy_tile_task_worker_pool.cc:53]
~~Dr.M~~ Note: #26 cc.dll!cc::`anonymous namespace'::RasterTaskImpl::Raster                   [cc\tiles\tile_manager.cc:131]
~~Dr.M~~ Note: #27 cc.dll!cc::`anonymous namespace'::RasterTaskImpl::RunOnWorkerThread        [cc\tiles\tile_manager.cc:90]
~~Dr.M~~ Note: #28 cc.dll!cc::TaskGraphRunner::RunTaskWithLockAcquired                        [cc\raster\task_graph_runner.cc:418]
~~Dr.M~~ Note: #29 cc.dll!cc::TaskGraphRunner::Run                                            [cc\raster\task_graph_runner.cc:361]
~~Dr.M~~ Note: #30 base.dll!base::SimpleThread::ThreadMain                                    [base\threading\simple_thread.cc:66]
~~Dr.M~~ Note: #31 base.dll!base::`anonymous namespace'::ThreadFunc                           [base\threading\platform_thread_win.cc:82]
~~Dr.M~~ Note: #32 KERNEL32.dll!BaseThreadInitThunk                                          +0x11     (0x7570337a <KERNEL32.dll+0x1337a>)

Original issue's description:
> Parallel cache.
>
> TBR=reed@google.com
>
> BUG=skia:1330
>
> Committed: https://skia.googlesource.com/skia/+/6f2a486040cb25465990196c229feb47e668e87f
>
> Committed: https://skia.googlesource.com/skia/+/bf2988833e5a36c6b430da6fdd2cfebd0015adec

TBR=reed@google.com,mtklein@google.com,mtklein@chromium.org,herb@google.com
BUG=skia:1330

[mtklein mucking around]
NOTREECHECKS=true

Review URL: https://codereview.chromium.org/1339493002
This commit is contained in:
jyasskin 2015-09-10 18:11:29 -07:00 committed by Commit bot
parent 83da2e28e2
commit 951d854327
9 changed files with 190 additions and 334 deletions

View File

@ -29,9 +29,6 @@ void sk_atomic_store(T*, T, sk_memory_order = sk_memory_order_seq_cst);
template <typename T> template <typename T>
T sk_atomic_fetch_add(T*, T, sk_memory_order = sk_memory_order_seq_cst); T sk_atomic_fetch_add(T*, T, sk_memory_order = sk_memory_order_seq_cst);
template <typename T>
T sk_atomic_fetch_sub(T*, T, sk_memory_order = sk_memory_order_seq_cst);
template <typename T> template <typename T>
bool sk_atomic_compare_exchange(T*, T* expected, T desired, bool sk_atomic_compare_exchange(T*, T* expected, T desired,
sk_memory_order success = sk_memory_order_seq_cst, sk_memory_order success = sk_memory_order_seq_cst,
@ -61,10 +58,6 @@ public:
return sk_atomic_fetch_add(&fVal, val, mo); return sk_atomic_fetch_add(&fVal, val, mo);
} }
T fetch_sub(const T& val, sk_memory_order mo = sk_memory_order_seq_cst) {
return sk_atomic_fetch_sub(&fVal, val, mo);
}
bool compare_exchange(T* expected, const T& desired, bool compare_exchange(T* expected, const T& desired,
sk_memory_order success = sk_memory_order_seq_cst, sk_memory_order success = sk_memory_order_seq_cst,
sk_memory_order failure = sk_memory_order_seq_cst) { sk_memory_order failure = sk_memory_order_seq_cst) {

View File

@ -31,12 +31,6 @@ T sk_atomic_fetch_add(T* ptr, T val, sk_memory_order mo) {
return __atomic_fetch_add(ptr, val, mo); return __atomic_fetch_add(ptr, val, mo);
} }
template <typename T>
T sk_atomic_fetch_sub(T* ptr, T val, sk_memory_order mo) {
// All values of mo are valid.
return __atomic_fetch_sub(ptr, val, mo);
}
template <typename T> template <typename T>
bool sk_atomic_compare_exchange(T* ptr, T* expected, T desired, bool sk_atomic_compare_exchange(T* ptr, T* expected, T desired,
sk_memory_order success, sk_memory_order success,

View File

@ -38,13 +38,6 @@ T sk_atomic_fetch_add(T* ptr, T val, sk_memory_order mo) {
return std::atomic_fetch_add_explicit(ap, val, (std::memory_order)mo); return std::atomic_fetch_add_explicit(ap, val, (std::memory_order)mo);
} }
template <typename T>
T sk_atomic_fetch_sub(T* ptr, T val, sk_memory_order mo) {
// All values of mo are valid.
std::atomic<T>* ap = reinterpret_cast<std::atomic<T>*>(ptr);
return std::atomic_fetch_sub_explicit(ap, val, (std::memory_order)mo);
}
template <typename T> template <typename T>
bool sk_atomic_compare_exchange(T* ptr, T* expected, T desired, bool sk_atomic_compare_exchange(T* ptr, T* expected, T desired,
sk_memory_order success, sk_memory_order success,

View File

@ -45,11 +45,6 @@ T sk_atomic_fetch_add(T* ptr, T val, sk_memory_order) {
return __sync_fetch_and_add(ptr, val); return __sync_fetch_and_add(ptr, val);
} }
template <typename T>
T sk_atomic_fetch_sub(T* ptr, T val, sk_memory_order) {
return __sync_fetch_and_sub(ptr, val);
}
template <typename T> template <typename T>
bool sk_atomic_compare_exchange(T* ptr, T* expected, T desired, sk_memory_order, sk_memory_order) { bool sk_atomic_compare_exchange(T* ptr, T* expected, T desired, sk_memory_order, sk_memory_order) {
T prev = __sync_val_compare_and_swap(ptr, *expected, desired); T prev = __sync_val_compare_and_swap(ptr, *expected, desired);

View File

@ -1476,12 +1476,14 @@ static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy,
bounds = &storage; bounds = &storage;
} }
uint8_t*aa = (uint8_t*)state.fCache->findImage(glyph); uint8_t* aa = (uint8_t*)glyph.fImage;
if (nullptr == aa) { if (nullptr == aa) {
return; // can't rasterize glyph aa = (uint8_t*)state.fCache->findImage(glyph);
if (nullptr == aa) {
return; // can't rasterize glyph
}
} }
mask.fRowBytes = glyph.rowBytes(); mask.fRowBytes = glyph.rowBytes();
mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
mask.fImage = aa; mask.fImage = aa;

View File

@ -47,8 +47,6 @@ class SkGlyph {
uint8_t fMaskFormat; uint8_t fMaskFormat;
int8_t fRsbDelta, fLsbDelta; // used by auto-kerning int8_t fRsbDelta, fLsbDelta; // used by auto-kerning
int8_t fForceBW; int8_t fForceBW;
mutable bool fImageIsSet;
mutable bool fPathIsSet;
void initWithGlyphID(uint32_t glyph_id) { void initWithGlyphID(uint32_t glyph_id) {
this->initCommon(MakeID(glyph_id)); this->initCommon(MakeID(glyph_id));
@ -137,8 +135,6 @@ class SkGlyph {
fPath = nullptr; fPath = nullptr;
fMaskFormat = MASK_FORMAT_UNKNOWN; fMaskFormat = MASK_FORMAT_UNKNOWN;
fForceBW = 0; fForceBW = 0;
fImageIsSet = false;
fPathIsSet = false;
} }
static unsigned ID2Code(uint32_t id) { static unsigned ID2Code(uint32_t id) {

View File

@ -8,7 +8,6 @@
#include "SkGlyphCache.h" #include "SkGlyphCache.h"
#include "SkGlyphCache_Globals.h" #include "SkGlyphCache_Globals.h"
#include "SkGraphics.h" #include "SkGraphics.h"
#include "SkOnce.h"
#include "SkOncePtr.h" #include "SkOncePtr.h"
#include "SkPath.h" #include "SkPath.h"
#include "SkTemplates.h" #include "SkTemplates.h"
@ -43,90 +42,42 @@ static SkGlyphCache_Globals& get_globals() {
#define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphCount) #define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphCount)
SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkScalerContext* ctx) SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkScalerContext* ctx)
: fNext(nullptr) : fDesc(desc->copy())
, fPrev(nullptr)
, fDesc(desc->copy())
, fRefCount(0)
, fGlyphAlloc(kMinAllocAmount)
, fMemoryUsed(sizeof(*this))
, fScalerContext(ctx) , fScalerContext(ctx)
, fAuxProcList(nullptr) { , fGlyphAlloc(kMinAllocAmount) {
SkASSERT(typeface); SkASSERT(typeface);
SkASSERT(desc); SkASSERT(desc);
SkASSERT(ctx); SkASSERT(ctx);
fPrev = fNext = nullptr;
fScalerContext->getFontMetrics(&fFontMetrics); fScalerContext->getFontMetrics(&fFontMetrics);
fMemoryUsed = sizeof(*this);
fAuxProcList = nullptr;
} }
SkGlyphCache::~SkGlyphCache() { SkGlyphCache::~SkGlyphCache() {
fGlyphMap.foreach ([](SkGlyph* g) { delete g->fPath; }); fGlyphMap.foreach ([](SkGlyph* g) { delete g->fPath; });
SkDescriptor::Free(fDesc); SkDescriptor::Free(fDesc);
delete fScalerContext; delete fScalerContext;
AuxProcRec* rec = fAuxProcList; this->invokeAndRemoveAuxProcs();
while (rec) {
rec->fProc(rec->fData);
AuxProcRec* next = rec->fNext;
delete rec;
rec = next;
}
}
void SkGlyphCache::increaseMemoryUsed(size_t used) {
fMemoryUsed += used;
get_globals().increaseTotalMemoryUsed(used);
}
SkGlyphCache::CharGlyphRec
SkGlyphCache::PackedUnicharIDtoCharGlyphRec(PackedUnicharID packedUnicharID) {
SkFixed x = SkGlyph::SubToFixed(SkGlyph::ID2SubX(packedUnicharID));
SkFixed y = SkGlyph::SubToFixed(SkGlyph::ID2SubY(packedUnicharID));
SkUnichar unichar = SkGlyph::ID2Code(packedUnicharID);
SkAutoMutexAcquire lock(fScalerMutex);
PackedGlyphID packedGlyphID = SkGlyph::MakeID(fScalerContext->charToGlyphID(unichar), x, y);
return {packedUnicharID, packedGlyphID};
} }
SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(PackedUnicharID packedUnicharID) { SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(PackedUnicharID packedUnicharID) {
if (nullptr == fPackedUnicharIDToPackedGlyphID.get()) { if (nullptr == fPackedUnicharIDToPackedGlyphID.get()) {
fMapMutex.releaseShared(); // Allocate the array.
fPackedUnicharIDToPackedGlyphID.reset(kHashCount);
// Add the map only if there is a call for char -> glyph mapping. // Initialize array to map character and position with the impossible glyph ID. This
{ // represents no mapping.
SkAutoTAcquire<SkSharedMutex> lock(fMapMutex); for (int i = 0; i <kHashCount; ++i) {
fPackedUnicharIDToPackedGlyphID[i].fPackedUnicharID = SkGlyph::kImpossibleID;
// Now that the cache is locked exclusively, make sure no one added this array fPackedUnicharIDToPackedGlyphID[i].fPackedGlyphID = 0;
// while unlocked.
if (nullptr == fPackedUnicharIDToPackedGlyphID.get()) {
// Allocate the array.
fPackedUnicharIDToPackedGlyphID.reset(new PackedUnicharIDToPackedGlyphIDMap);
}
fPackedUnicharIDToPackedGlyphID->set(PackedUnicharIDtoCharGlyphRec(packedUnicharID));
} }
fMapMutex.acquireShared();
return fPackedUnicharIDToPackedGlyphID->find(packedUnicharID);
} }
CharGlyphRec* answer = fPackedUnicharIDToPackedGlyphID->find(packedUnicharID); return &fPackedUnicharIDToPackedGlyphID[SkChecksum::CheapMix(packedUnicharID) & kHashMask];
if (nullptr == answer) {
fMapMutex.releaseShared();
// Add a new char -> glyph mapping.
{
SkAutoTAcquire<SkSharedMutex> lock(fMapMutex);
answer = fPackedUnicharIDToPackedGlyphID->find(packedUnicharID);
if (nullptr == answer) {
fPackedUnicharIDToPackedGlyphID->set(
PackedUnicharIDtoCharGlyphRec(packedUnicharID));
}
}
fMapMutex.acquireShared();
return fPackedUnicharIDToPackedGlyphID->find(packedUnicharID);
}
return answer;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -141,11 +92,15 @@ uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) {
VALIDATE(); VALIDATE();
PackedUnicharID packedUnicharID = SkGlyph::MakeID(charCode); PackedUnicharID packedUnicharID = SkGlyph::MakeID(charCode);
const CharGlyphRec& rec = *this->getCharGlyphRec(packedUnicharID); const CharGlyphRec& rec = *this->getCharGlyphRec(packedUnicharID);
return SkGlyph::ID2Code(rec.fPackedGlyphID);
if (rec.fPackedUnicharID == packedUnicharID) {
return SkGlyph::ID2Code(rec.fPackedGlyphID);
} else {
return fScalerContext->charToGlyphID(charCode);
}
} }
SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) { SkUnichar SkGlyphCache::glyphToUnichar(uint16_t glyphID) {
SkAutoMutexAcquire lock(fScalerMutex);
return fScalerContext->glyphIDToChar(glyphID); return fScalerContext->glyphIDToChar(glyphID);
} }
@ -159,19 +114,19 @@ int SkGlyphCache::countCachedGlyphs() const {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, SkFixed x, SkFixed y) {
PackedUnicharID targetUnicharID = SkGlyph::MakeID(charCode, x, y);
CharGlyphRec* rec = this->getCharGlyphRec(targetUnicharID);
PackedGlyphID packedGlyphID = rec->fPackedGlyphID;
return this->lookupByPackedGlyphID(packedGlyphID);
}
const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) { const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) {
VALIDATE(); VALIDATE();
return *this->lookupByChar(charCode); return *this->lookupByChar(charCode);
} }
const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) {
VALIDATE();
PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID);
return *this->lookupByPackedGlyphID(packedGlyphID);
}
///////////////////////////////////////////////////////////////////////////////
const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) { const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) {
VALIDATE(); VALIDATE();
return *this->lookupByChar(charCode); return *this->lookupByChar(charCode);
@ -182,49 +137,6 @@ const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode, SkFixed x, Sk
return *this->lookupByChar(charCode, x, y); return *this->lookupByChar(charCode, x, y);
} }
///////////////////////////////////////////////////////////////////////////////
SkGlyph* SkGlyphCache::allocateNewGlyph(PackedGlyphID packedGlyphID) {
SkGlyph* glyphPtr;
{
fMapMutex.releaseShared();
{
SkAutoTAcquire<SkSharedMutex> mapLock(fMapMutex);
glyphPtr = fGlyphMap.find(packedGlyphID);
if (nullptr == glyphPtr) {
SkGlyph glyph;
glyph.initGlyphFromCombinedID(packedGlyphID);
{
SkAutoMutexAcquire lock(fScalerMutex);
fScalerContext->getMetrics(&glyph);
this->increaseMemoryUsed(sizeof(SkGlyph));
glyphPtr = fGlyphMap.set(glyph);
} // drop scaler lock
}
} // drop map lock
fMapMutex.acquireShared();
glyphPtr = fGlyphMap.find(packedGlyphID);
}
SkASSERT(glyphPtr->fID != SkGlyph::kImpossibleID);
return glyphPtr;
}
SkGlyph* SkGlyphCache::lookupByPackedGlyphID(PackedGlyphID packedGlyphID) {
SkGlyph* glyph = fGlyphMap.find(packedGlyphID);
if (nullptr == glyph) {
glyph = this->allocateNewGlyph(packedGlyphID);
}
return glyph;
}
const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) {
VALIDATE();
PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID);
return *this->lookupByPackedGlyphID(packedGlyphID);
}
const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) { const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) {
VALIDATE(); VALIDATE();
PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID); PackedGlyphID packedGlyphID = SkGlyph::MakeID(glyphID);
@ -237,46 +149,74 @@ const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFi
return *this->lookupByPackedGlyphID(packedGlyphID); return *this->lookupByPackedGlyphID(packedGlyphID);
} }
/////////////////////////////////////////////////////////////////////////////// SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, SkFixed x, SkFixed y) {
PackedUnicharID id = SkGlyph::MakeID(charCode, x, y);
void SkGlyphCache::OnceFillInImage(GlyphAndCache gc) { CharGlyphRec* rec = this->getCharGlyphRec(id);
SkGlyphCache* cache = gc.cache; if (rec->fPackedUnicharID != id) {
const SkGlyph* glyph = gc.glyph; // this ID is based on the UniChar
cache->fScalerMutex.assertHeld(); rec->fPackedUnicharID = id;
if (glyph->fWidth > 0 && glyph->fWidth < kMaxGlyphWidth) { // this ID is based on the glyph index
size_t size = glyph->computeImageSize(); PackedGlyphID combinedID = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode), x, y);
sk_atomic_store(&const_cast<SkGlyph*>(glyph)->fImage, rec->fPackedGlyphID = combinedID;
cache->fGlyphAlloc.alloc(size, SkChunkAlloc::kReturnNil_AllocFailType), return this->lookupByPackedGlyphID(combinedID);
sk_memory_order_relaxed); } else {
if (glyph->fImage != nullptr) { return this->lookupByPackedGlyphID(rec->fPackedGlyphID);
cache->fScalerContext->getImage(*glyph);
cache->increaseMemoryUsed(size);
}
} }
} }
SkGlyph* SkGlyphCache::lookupByPackedGlyphID(PackedGlyphID packedGlyphID) {
SkGlyph* glyph = fGlyphMap.find(packedGlyphID);
if (nullptr == glyph) {
glyph = this->allocateNewGlyph(packedGlyphID);
}
return glyph;
}
SkGlyph* SkGlyphCache::allocateNewGlyph(PackedGlyphID packedGlyphID) {
fMemoryUsed += sizeof(SkGlyph);
SkGlyph* glyphPtr;
{
SkGlyph glyph;
glyph.initGlyphFromCombinedID(packedGlyphID);
glyphPtr = fGlyphMap.set(glyph);
}
fScalerContext->getMetrics(glyphPtr);
SkASSERT(glyphPtr->fID != SkGlyph::kImpossibleID);
return glyphPtr;
}
const void* SkGlyphCache::findImage(const SkGlyph& glyph) { const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
SkOnce<SkMutex, GlyphAndCache>( if (glyph.fWidth > 0 && glyph.fWidth < kMaxGlyphWidth) {
&glyph.fImageIsSet, &fScalerMutex, &SkGlyphCache::OnceFillInImage, {this, &glyph}); if (nullptr == glyph.fImage) {
return sk_atomic_load(&glyph.fImage, sk_memory_order_seq_cst); size_t size = glyph.computeImageSize();
} const_cast<SkGlyph&>(glyph).fImage = fGlyphAlloc.alloc(size,
SkChunkAlloc::kReturnNil_AllocFailType);
void SkGlyphCache::OnceFillInPath(GlyphAndCache gc) { // check that alloc() actually succeeded
SkGlyphCache* cache = gc.cache; if (glyph.fImage) {
const SkGlyph* glyph = gc.glyph; fScalerContext->getImage(glyph);
cache->fScalerMutex.assertHeld(); // TODO: the scaler may have changed the maskformat during
if (glyph->fWidth > 0) { // getImage (e.g. from AA or LCD to BW) which means we may have
sk_atomic_store(&const_cast<SkGlyph*>(glyph)->fPath, new SkPath, sk_memory_order_relaxed); // overallocated the buffer. Check if the new computedImageSize
cache->fScalerContext->getPath(*glyph, glyph->fPath); // is smaller, and if so, strink the alloc size in fImageAlloc.
size_t size = sizeof(SkPath) + glyph->fPath->countPoints() * sizeof(SkPoint); fMemoryUsed += size;
cache->increaseMemoryUsed(size); }
}
} }
return glyph.fImage;
} }
const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) { const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) {
SkOnce<SkMutex, GlyphAndCache>( if (glyph.fWidth) {
&glyph.fPathIsSet, &fScalerMutex, &SkGlyphCache::OnceFillInPath, {this, &glyph}); if (glyph.fPath == nullptr) {
return sk_atomic_load(&glyph.fPath, sk_memory_order_seq_cst); const_cast<SkGlyph&>(glyph).fPath = new SkPath;
fScalerContext->getPath(glyph, glyph.fPath);
fMemoryUsed += sizeof(SkPath) +
glyph.fPath->countPoints() * sizeof(SkPoint);
}
}
return glyph.fPath;
} }
void SkGlyphCache::dump() const { void SkGlyphCache::dump() const {
@ -289,22 +229,18 @@ void SkGlyphCache::dump() const {
face->getFamilyName(&name); face->getFamilyName(&name);
SkString msg; SkString msg;
msg.printf( msg.printf("cache typeface:%x %25s:%d size:%2g [%g %g %g %g] lum:%02X devG:%d pntG:%d cntr:%d glyphs:%3d",
"cache typeface:%x %25s:%d size:%2g [%g %g %g %g] " face->uniqueID(), name.c_str(), face->style(), rec.fTextSize,
"lum:%02X devG:%d pntG:%d cntr:%d glyphs:%3d", matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX],
face->uniqueID(), name.c_str(), face->style(), rec.fTextSize, matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY],
matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX], rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fContrast,
matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY], fGlyphMap.count());
rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fContrast,
fGlyphMap.count());
SkDebugf("%s\n", msg.c_str()); SkDebugf("%s\n", msg.c_str());
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const { bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const {
// Borrow the fScalerMutex to protect the AuxProc list.
SkAutoMutexAcquire lock(fScalerMutex);
const AuxProcRec* rec = fAuxProcList; const AuxProcRec* rec = fAuxProcList;
while (rec) { while (rec) {
if (rec->fProc == proc) { if (rec->fProc == proc) {
@ -323,8 +259,6 @@ void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) {
return; return;
} }
// Borrow the fScalerMutex to protect the AuxProc linked list.
SkAutoMutexAcquire lock(fScalerMutex);
AuxProcRec* rec = fAuxProcList; AuxProcRec* rec = fAuxProcList;
while (rec) { while (rec) {
if (rec->fProc == proc) { if (rec->fProc == proc) {
@ -341,9 +275,27 @@ void SkGlyphCache::setAuxProc(void (*proc)(void*), void* data) {
fAuxProcList = rec; fAuxProcList = rec;
} }
void SkGlyphCache::invokeAndRemoveAuxProcs() {
AuxProcRec* rec = fAuxProcList;
while (rec) {
rec->fProc(rec->fData);
AuxProcRec* next = rec->fNext;
delete rec;
rec = next;
}
}
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
typedef SkAutoTAcquire<SkSpinlock> AutoAcquire;
class AutoAcquire {
public:
AutoAcquire(SkSpinlock& lock) : fLock(lock) { fLock.acquire(); }
~AutoAcquire() { fLock.release(); }
private:
SkSpinlock& fLock;
};
size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) {
static const size_t minLimit = 256 * 1024; static const size_t minLimit = 256 * 1024;
@ -374,7 +326,7 @@ int SkGlyphCache_Globals::setCacheCountLimit(int newCount) {
void SkGlyphCache_Globals::purgeAll() { void SkGlyphCache_Globals::purgeAll() {
AutoAcquire ac(fLock); AutoAcquire ac(fLock);
this->internalPurge(fTotalMemoryUsed.load()); this->internalPurge(fTotalMemoryUsed);
} }
/* This guy calls the visitor from within the mutext lock, so the visitor /* This guy calls the visitor from within the mutext lock, so the visitor
@ -383,8 +335,10 @@ void SkGlyphCache_Globals::purgeAll() {
- try to acquire the mutext again - try to acquire the mutext again
- call a fontscaler (which might call into the cache) - call a fontscaler (which might call into the cache)
*/ */
SkGlyphCache* SkGlyphCache::VisitCache( SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface,
SkTypeface* typeface, const SkDescriptor* desc, VisitProc proc, void* context) { const SkDescriptor* desc,
bool (*proc)(const SkGlyphCache*, void*),
void* context) {
if (!typeface) { if (!typeface) {
typeface = SkTypeface::GetDefaultTypeface(); typeface = SkTypeface::GetDefaultTypeface();
} }
@ -400,15 +354,11 @@ SkGlyphCache* SkGlyphCache::VisitCache(
for (cache = globals.internalGetHead(); cache != nullptr; cache = cache->fNext) { for (cache = globals.internalGetHead(); cache != nullptr; cache = cache->fNext) {
if (cache->fDesc->equals(*desc)) { if (cache->fDesc->equals(*desc)) {
globals.internalMoveToHead(cache); globals.internalDetachCache(cache);
cache->fMapMutex.acquireShared();
if (!proc(cache, context)) { if (!proc(cache, context)) {
cache->fMapMutex.releaseShared(); globals.internalAttachCacheToHead(cache);
return nullptr; cache = nullptr;
} }
// The caller will take reference on this SkGlyphCache, and the corresponding
// Attach call will decrement the reference.
cache->fRefCount += 1;
return cache; return cache;
} }
} }
@ -421,43 +371,28 @@ SkGlyphCache* SkGlyphCache::VisitCache(
// pass true the first time, to notice if the scalercontext failed, // pass true the first time, to notice if the scalercontext failed,
// so we can try the purge. // so we can try the purge.
SkScalerContext* ctx = typeface->createScalerContext(desc, true); SkScalerContext* ctx = typeface->createScalerContext(desc, true);
if (nullptr == ctx) { if (!ctx) {
get_globals().purgeAll(); get_globals().purgeAll();
ctx = typeface->createScalerContext(desc, false); ctx = typeface->createScalerContext(desc, false);
SkASSERT(ctx); SkASSERT(ctx);
} }
cache = new SkGlyphCache(typeface, desc, ctx); cache = new SkGlyphCache(typeface, desc, ctx);
} }
AutoAcquire ac(globals.fLock); AutoValidate av(cache);
globals.internalAttachCacheToHead(cache);
cache->fMapMutex.acquireShared();
if (!proc(cache, context)) { // need to reattach if (!proc(cache, context)) { // need to reattach
cache->fMapMutex.releaseShared(); globals.attachCacheToHead(cache);
return nullptr; cache = nullptr;
} }
// The caller will take reference on this SkGlyphCache, and the corresponding
// Attach call will decrement the reference.
cache->fRefCount += 1;
return cache; return cache;
} }
void SkGlyphCache::AttachCache(SkGlyphCache* cache) { void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
SkASSERT(cache); SkASSERT(cache);
cache->fMapMutex.releaseShared(); SkASSERT(cache->fNext == nullptr);
SkGlyphCache_Globals& globals = get_globals();
AutoAcquire ac(globals.fLock);
globals.validate();
cache->validate();
// Unref and delete if no longer in the LRU list. get_globals().attachCacheToHead(cache);
cache->fRefCount -= 1;
if (cache->fRefCount == 0) {
delete cache;
}
globals.internalPurge();
} }
static void dump_visitor(const SkGlyphCache& cache, void* context) { static void dump_visitor(const SkGlyphCache& cache, void* context) {
@ -532,17 +467,14 @@ void SkGlyphCache::VisitAll(Visitor visitor, void* context) {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void SkGlyphCache_Globals::internalAttachCacheToHead(SkGlyphCache* cache) { void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) {
this->internalPurge(); AutoAcquire ac(fLock);
fCacheCount += 1;
cache->fRefCount += 1;
// Access to cache->fMemoryUsed is single threaded until internalMoveToHead.
fTotalMemoryUsed.fetch_add(cache->fMemoryUsed);
this->internalMoveToHead(cache);
this->validate(); this->validate();
cache->validate(); cache->validate();
this->internalAttachCacheToHead(cache);
this->internalPurge();
} }
SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const { SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const {
@ -559,13 +491,13 @@ size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) {
this->validate(); this->validate();
size_t bytesNeeded = 0; size_t bytesNeeded = 0;
if (fTotalMemoryUsed.load() > fCacheSizeLimit) { if (fTotalMemoryUsed > fCacheSizeLimit) {
bytesNeeded = fTotalMemoryUsed.load() - fCacheSizeLimit; bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit;
} }
bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded); bytesNeeded = SkTMax(bytesNeeded, minBytesNeeded);
if (bytesNeeded) { if (bytesNeeded) {
// no small purges! // no small purges!
bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed.load() >> 2); bytesNeeded = SkTMax(bytesNeeded, fTotalMemoryUsed >> 2);
} }
int countNeeded = 0; int countNeeded = 0;
@ -591,10 +523,9 @@ size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) {
SkGlyphCache* prev = cache->fPrev; SkGlyphCache* prev = cache->fPrev;
bytesFreed += cache->fMemoryUsed; bytesFreed += cache->fMemoryUsed;
countFreed += 1; countFreed += 1;
this->internalDetachCache(cache); this->internalDetachCache(cache);
if (0 == cache->fRefCount) { delete cache;
delete cache;
}
cache = prev; cache = prev;
} }
@ -610,50 +541,34 @@ size_t SkGlyphCache_Globals::internalPurge(size_t minBytesNeeded) {
return bytesFreed; return bytesFreed;
} }
void SkGlyphCache_Globals::internalMoveToHead(SkGlyphCache *cache) { void SkGlyphCache_Globals::internalAttachCacheToHead(SkGlyphCache* cache) {
if (cache != fHead) { SkASSERT(nullptr == cache->fPrev && nullptr == cache->fNext);
if (cache->fPrev) { if (fHead) {
cache->fPrev->fNext = cache->fNext; fHead->fPrev = cache;
} cache->fNext = fHead;
if (cache->fNext) {
cache->fNext->fPrev = cache->fPrev;
}
cache->fNext = nullptr;
cache->fPrev = nullptr;
if (fHead) {
fHead->fPrev = cache;
cache->fNext = fHead;
}
fHead = cache;
} }
fHead = cache;
fCacheCount += 1;
fTotalMemoryUsed += cache->fMemoryUsed;
} }
void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) { void SkGlyphCache_Globals::internalDetachCache(SkGlyphCache* cache) {
SkASSERT(fCacheCount > 0);
fCacheCount -= 1; fCacheCount -= 1;
fTotalMemoryUsed.fetch_sub(cache->fMemoryUsed); fTotalMemoryUsed -= cache->fMemoryUsed;
if (cache->fPrev) { if (cache->fPrev) {
cache->fPrev->fNext = cache->fNext; cache->fPrev->fNext = cache->fNext;
} else { } else {
// If cache->fPrev == nullptr then this is the head node.
fHead = cache->fNext; fHead = cache->fNext;
if (fHead != nullptr) {
fHead->fPrev = nullptr;
}
} }
if (cache->fNext) { if (cache->fNext) {
cache->fNext->fPrev = cache->fPrev; cache->fNext->fPrev = cache->fPrev;
} else {
// If cache->fNext == nullptr then this is the last node.
if (cache->fPrev != nullptr) {
cache->fPrev->fNext = nullptr;
}
} }
cache->fPrev = cache->fNext = nullptr; cache->fPrev = cache->fNext = nullptr;
cache->fRefCount -= 1;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG #ifdef SK_DEBUG
@ -672,16 +587,20 @@ void SkGlyphCache::validate() const {
} }
void SkGlyphCache_Globals::validate() const { void SkGlyphCache_Globals::validate() const {
size_t computedBytes = 0;
int computedCount = 0; int computedCount = 0;
SkGlyphCache* head = fHead; const SkGlyphCache* head = fHead;
while (head != nullptr) { while (head != nullptr) {
computedBytes += head->fMemoryUsed;
computedCount += 1; computedCount += 1;
head = head->fNext; head = head->fNext;
} }
SkASSERTF(fCacheCount == computedCount, "fCacheCount: %d, computedCount: %d", fCacheCount, SkASSERTF(fCacheCount == computedCount, "fCacheCount: %d, computedCount: %d", fCacheCount,
computedCount); computedCount);
SkASSERTF(fTotalMemoryUsed == computedBytes, "fTotalMemoryUsed: %d, computedBytes: %d",
fTotalMemoryUsed, computedBytes);
} }
#endif #endif

View File

@ -11,11 +11,8 @@
#include "SkChunkAlloc.h" #include "SkChunkAlloc.h"
#include "SkDescriptor.h" #include "SkDescriptor.h"
#include "SkGlyph.h" #include "SkGlyph.h"
#include "SkMutex.h"
#include "SkTHash.h" #include "SkTHash.h"
#include "SkScalerContext.h" #include "SkScalerContext.h"
#include "SkSharedMutex.h"
#include "SkSpinlock.h"
#include "SkTemplates.h" #include "SkTemplates.h"
#include "SkTDArray.h" #include "SkTDArray.h"
@ -122,23 +119,12 @@ public:
SkScalerContext* getScalerContext() const { return fScalerContext; } SkScalerContext* getScalerContext() const { return fScalerContext; }
struct GlyphAndCache {
SkGlyphCache* cache;
const SkGlyph* glyph;
};
static void OnceFillInImage(GlyphAndCache gc);
static void OnceFillInPath(GlyphAndCache gc);
typedef bool (*VisitProc)(const SkGlyphCache*, void*);
/** Find a matching cache entry, and call proc() with it. If none is found create a new one. /** Find a matching cache entry, and call proc() with it. If none is found create a new one.
If the proc() returns true, detach the cache and return it, otherwise leave it and return If the proc() returns true, detach the cache and return it, otherwise leave it and return
nullptr. nullptr.
*/ */
static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc,
VisitProc proc, bool (*proc)(const SkGlyphCache*, void*),
void* context); void* context);
/** Given a strike that was returned by either VisitCache() or DetachCache() add it back into /** Given a strike that was returned by either VisitCache() or DetachCache() add it back into
@ -195,21 +181,18 @@ public:
private: private:
friend class SkGlyphCache_Globals; friend class SkGlyphCache_Globals;
enum {
kHashBits = 8,
kHashCount = 1 << kHashBits,
kHashMask = kHashCount - 1
};
typedef uint32_t PackedGlyphID; // glyph-index + subpixel-pos typedef uint32_t PackedGlyphID; // glyph-index + subpixel-pos
typedef uint32_t PackedUnicharID; // unichar + subpixel-pos typedef uint32_t PackedUnicharID; // unichar + subpixel-pos
struct CharGlyphRec { struct CharGlyphRec {
class HashTraits { PackedUnicharID fPackedUnicharID;
public: PackedGlyphID fPackedGlyphID;
static PackedUnicharID GetKey(const CharGlyphRec& rec) {
return rec.fPackedUnicharID;
}
static uint32_t Hash(PackedUnicharID unicharID) {
return SkChecksum::CheapMix(unicharID);
}
};
PackedUnicharID fPackedUnicharID;
PackedGlyphID fPackedGlyphID;
}; };
struct AuxProcRec { struct AuxProcRec {
@ -222,9 +205,6 @@ private:
SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*); SkGlyphCache(SkTypeface*, const SkDescriptor*, SkScalerContext*);
~SkGlyphCache(); ~SkGlyphCache();
// Increase the memory used keeping the cache and the global size in sync.
void increaseMemoryUsed(size_t used);
// Return the SkGlyph* associated with MakeID. The id parameter is the // Return the SkGlyph* associated with MakeID. The id parameter is the
// combined glyph/x/y id generated by MakeID. If it is just a glyph id // combined glyph/x/y id generated by MakeID. If it is just a glyph id
// then x and y are assumed to be zero. // then x and y are assumed to be zero.
@ -236,45 +216,32 @@ private:
// Return a new SkGlyph for the glyph ID and subpixel position id. // Return a new SkGlyph for the glyph ID and subpixel position id.
SkGlyph* allocateNewGlyph(PackedGlyphID packedGlyphID); SkGlyph* allocateNewGlyph(PackedGlyphID packedGlyphID);
// Add the full metrics to an existing glyph.
void addFullMetrics(SkGlyph* glyph);
static bool DetachProc(const SkGlyphCache*, void*) { return true; } static bool DetachProc(const SkGlyphCache*, void*) { return true; }
CharGlyphRec PackedUnicharIDtoCharGlyphRec(PackedUnicharID packedUnicharID);
// The id arg is a combined id generated by MakeID. // The id arg is a combined id generated by MakeID.
CharGlyphRec* getCharGlyphRec(PackedUnicharID id); CharGlyphRec* getCharGlyphRec(PackedUnicharID id);
void invokeAndRemoveAuxProcs();
inline static SkGlyphCache* FindTail(SkGlyphCache* head); inline static SkGlyphCache* FindTail(SkGlyphCache* head);
// The following are protected by the SkGlyphCache_Globals fLock mutex.
// Note: the following fields are protected by a mutex in a different class.
SkGlyphCache* fNext; SkGlyphCache* fNext;
SkGlyphCache* fPrev; SkGlyphCache* fPrev;
SkDescriptor* const fDesc; SkDescriptor* const fDesc;
SkScalerContext* const fScalerContext;
SkPaint::FontMetrics fFontMetrics; SkPaint::FontMetrics fFontMetrics;
int fRefCount;
// The following fields are protected by fMapMutex.
mutable SkSharedMutex fMapMutex;
// Map from a combined GlyphID and sub-pixel position to a SkGlyph. // Map from a combined GlyphID and sub-pixel position to a SkGlyph.
SkTHashTable<SkGlyph, PackedGlyphID, SkGlyph::HashTraits> fGlyphMap; SkTHashTable<SkGlyph, PackedGlyphID, SkGlyph::HashTraits> fGlyphMap;
SkChunkAlloc fGlyphAlloc; SkChunkAlloc fGlyphAlloc;
typedef SkTHashTable<CharGlyphRec, PackedUnicharID, CharGlyphRec::HashTraits>
PackedUnicharIDToPackedGlyphIDMap; SkAutoTArray<CharGlyphRec> fPackedUnicharIDToPackedGlyphID;
SkAutoTDelete<PackedUnicharIDToPackedGlyphIDMap> fPackedUnicharIDToPackedGlyphID;
// used to track (approx) how much ram is tied-up in this cache // used to track (approx) how much ram is tied-up in this cache
size_t fMemoryUsed; size_t fMemoryUsed;
// The FScalerMutex protects the following fields. It is mainly used to ensure single-threaded
// access to the font scaler, but it also protects the fAuxProcList.
mutable SkMutex fScalerMutex;
SkScalerContext* const fScalerContext;
AuxProcRec* fAuxProcList; AuxProcRec* fAuxProcList;
// BEWARE: Mutex ordering
// If you need to hold both fMapMutex and fScalerMutex then fMapMutex must be held first.
}; };
class SkAutoGlyphCacheBase { class SkAutoGlyphCacheBase {

View File

@ -26,9 +26,8 @@
class SkGlyphCache_Globals { class SkGlyphCache_Globals {
public: public:
SkGlyphCache_Globals() { SkGlyphCache_Globals() {
fHead = nullptr; fHead = nullptr;
fTotalMemoryUsed.store(0); fTotalMemoryUsed = 0;
fCacheSizeLimit = SK_DEFAULT_FONT_CACHE_LIMIT; fCacheSizeLimit = SK_DEFAULT_FONT_CACHE_LIMIT;
fCacheCount = 0; fCacheCount = 0;
fCacheCountLimit = SK_DEFAULT_FONT_CACHE_COUNT_LIMIT; fCacheCountLimit = SK_DEFAULT_FONT_CACHE_COUNT_LIMIT;
@ -48,8 +47,7 @@ public:
SkGlyphCache* internalGetHead() const { return fHead; } SkGlyphCache* internalGetHead() const { return fHead; }
SkGlyphCache* internalGetTail() const; SkGlyphCache* internalGetTail() const;
size_t getTotalMemoryUsed() const { return fTotalMemoryUsed.load(); } size_t getTotalMemoryUsed() const { return fTotalMemoryUsed; }
void increaseTotalMemoryUsed(size_t increase) { fTotalMemoryUsed.fetch_add(increase);}
int getCacheCountUsed() const { return fCacheCount; } int getCacheCountUsed() const { return fCacheCount; }
#ifdef SK_DEBUG #ifdef SK_DEBUG
@ -68,30 +66,29 @@ public:
// or count limit. // or count limit.
bool isOverBudget() const { bool isOverBudget() const {
return fCacheCount > fCacheCountLimit || return fCacheCount > fCacheCountLimit ||
fTotalMemoryUsed.load() > fCacheSizeLimit; fTotalMemoryUsed > fCacheSizeLimit;
} }
void purgeAll(); // does not change budget void purgeAll(); // does not change budget
// call when a glyphcache is available for caching (i.e. not in use) // call when a glyphcache is available for caching (i.e. not in use)
void internalAttachCacheToHead(SkGlyphCache*); void attachCacheToHead(SkGlyphCache*);
// can only be called when the mutex is already held // can only be called when the mutex is already held
void internalMoveToHead(SkGlyphCache *); void internalDetachCache(SkGlyphCache*);
void internalAttachCacheToHead(SkGlyphCache*);
private:
SkGlyphCache* fHead;
size_t fTotalMemoryUsed;
size_t fCacheSizeLimit;
int32_t fCacheCountLimit;
int32_t fCacheCount;
// Checkout budgets, modulated by the specified min-bytes-needed-to-purge, // Checkout budgets, modulated by the specified min-bytes-needed-to-purge,
// and attempt to purge caches to match. // and attempt to purge caches to match.
// Returns number of bytes freed. // Returns number of bytes freed.
void internalDetachCache(SkGlyphCache* cache);
size_t internalPurge(size_t minBytesNeeded = 0); size_t internalPurge(size_t minBytesNeeded = 0);
private:
SkGlyphCache* fHead;
SkAtomic<size_t> fTotalMemoryUsed;
size_t fCacheSizeLimit;
int32_t fCacheCountLimit;
int32_t fCacheCount;
}; };
#endif #endif