Skip to content

Commit 7f669db

Browse files
authored
Refactor SpriteFrameCache to use uint64_t as map key (#2444)
1 parent bb3416a commit 7f669db

File tree

5 files changed

+86
-72
lines changed

5 files changed

+86
-72
lines changed

core/2d/SpriteFrame.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ namespace ax
3939
{
4040

4141
class Texture2D;
42-
42+
class SpriteFrameCache;
4343
/**
4444
* @addtogroup _2d
4545
* @{
@@ -60,6 +60,8 @@ class Texture2D;
6060
*/
6161
class AX_DLL SpriteFrame : public Object, public Clonable
6262
{
63+
friend class SpriteFrameCache;
64+
6365
public:
6466
/** Create a SpriteFrame with a texture filename, rect in points.
6567
It is assumed that the frame was not trimmed.
@@ -302,7 +304,12 @@ class AX_DLL SpriteFrame : public Object, public Clonable
302304
const Vec2& offset,
303305
const Vec2& originalSize);
304306

307+
// @since axmol-2.5.0
308+
std::string_view getName() { return _name; }
309+
305310
protected:
311+
void setName(std::string_view name) { _name = name; }
312+
306313
Vec2 _offset;
307314
Vec2 _anchorPoint;
308315
Vec2 _originalSize;
@@ -313,6 +320,7 @@ class AX_DLL SpriteFrame : public Object, public Clonable
313320
Vec2 _offsetInPixels;
314321
Vec2 _originalSizeInPixels;
315322
Texture2D* _texture;
323+
std::string _name;
316324
std::string _textureFilename;
317325
PolygonInfo _polygonInfo;
318326
};

core/2d/SpriteFrameCache.cpp

Lines changed: 55 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ THE SOFTWARE.
4141
#include "base/Director.h"
4242
#include "renderer/Texture2D.h"
4343
#include "base/NinePatchImageParser.h"
44+
#include "xxhash.h"
4445

4546
using namespace std;
4647

@@ -49,6 +50,11 @@ namespace ax
4950

5051
static SpriteFrameCache* _sharedSpriteFrameCache = nullptr;
5152

53+
static uint64_t computeHash(const std::string_view& v)
54+
{
55+
return XXH64(v.data(), v.length(), 0);
56+
}
57+
5258
SpriteFrameCache* SpriteFrameCache::getInstance()
5359
{
5460
if (!_sharedSpriteFrameCache)
@@ -121,15 +127,16 @@ void SpriteFrameCache::addSpriteFramesWithFileContent(const Data& content,
121127

122128
bool SpriteFrameCache::isSpriteFramesWithFileLoaded(std::string_view plist) const
123129
{
124-
return isSpriteSheetInUse(plist) && isPlistFull(plist);
130+
auto sheetId = computeHash(plist);
131+
return isSpriteSheetInUse(sheetId) && isPlistFull(sheetId);
125132
}
126133

127134
void SpriteFrameCache::addSpriteFrame(SpriteFrame* frame, std::string_view frameName)
128135
{
129136
AXASSERT(frame, "frame should not be nil");
130137

131-
const std::string name = "by#addSpriteFrame()";
132-
auto&& itr = _spriteSheets.find(name);
138+
const auto name = computeHash("by#addSpriteFrame()");
139+
auto&& itr = _spriteSheets.find(name);
133140
if (itr != _spriteSheets.end())
134141
{
135142
insertFrame(itr->second, frameName, frame);
@@ -150,7 +157,7 @@ void SpriteFrameCache::removeSpriteFrames()
150157
void SpriteFrameCache::removeUnusedSpriteFrames()
151158
{
152159
auto removed = false;
153-
std::vector<std::string_view> toRemoveFrames;
160+
std::vector<uint64_t> toRemoveFrames;
154161

155162
const auto& frames = getSpriteFrames();
156163
for (auto&& iter : frames)
@@ -173,13 +180,13 @@ void SpriteFrameCache::removeUnusedSpriteFrames()
173180

174181
void SpriteFrameCache::removeUnusedSpriteSheets()
175182
{
176-
std::vector<std::string_view> willRemoveSpriteSheetFileNames;
183+
std::vector<uint64_t> willRemoveSpriteSheetFileNames;
177184
for (auto&& it : _spriteSheets)
178185
{
179186
bool isUsed = false;
180187
for (auto&& frame : it.second->frames)
181188
{
182-
auto spriteFrame = getSpriteFrameByName(frame);
189+
auto spriteFrame = findFrame(frame);
183190
if (spriteFrame && spriteFrame->getReferenceCount() > 1)
184191
{
185192
isUsed = true;
@@ -191,10 +198,10 @@ void SpriteFrameCache::removeUnusedSpriteSheets()
191198
willRemoveSpriteSheetFileNames.push_back(it.first);
192199
}
193200

194-
for (auto& spriteSheetFileName : willRemoveSpriteSheetFileNames)
201+
for (auto& sheetId : willRemoveSpriteSheetFileNames)
195202
{
196-
AXLOGD("SpriteFrameCache: removing unused sprite sheet file : {}", spriteSheetFileName);
197-
removeSpriteSheet(spriteSheetFileName);
203+
AXLOGD("SpriteFrameCache: removing unused sprite sheet file : {}", sheetId);
204+
removeSpriteSheet(sheetId);
198205
}
199206
}
200207

@@ -219,7 +226,7 @@ void SpriteFrameCache::removeSpriteFramesFromFile(std::string_view atlasPath)
219226
// removeSpriteFramesFromDictionary(dict);
220227

221228
// remove it from the cache
222-
removeSpriteSheet(atlasPath);
229+
removeSpriteSheet(computeHash(atlasPath));
223230
}
224231

225232
void SpriteFrameCache::removeSpriteFramesFromFileContent(std::string_view plist_content)
@@ -240,13 +247,14 @@ void SpriteFrameCache::removeSpriteFramesFromDictionary(ValueMap& dictionary)
240247
return;
241248

242249
const auto& framesDict = dictionary["frames"].asValueMap();
243-
std::vector<std::string_view> keysToRemove;
250+
std::vector<uint64_t> keysToRemove;
244251

245252
for (const auto& iter : framesDict)
246253
{
247-
if (findFrame(iter.first))
254+
auto frameId = computeHash(iter.first);
255+
if (findFrame(frameId))
248256
{
249-
keysToRemove.emplace_back(iter.first);
257+
keysToRemove.emplace_back(frameId);
250258
}
251259
}
252260

@@ -255,7 +263,7 @@ void SpriteFrameCache::removeSpriteFramesFromDictionary(ValueMap& dictionary)
255263

256264
void SpriteFrameCache::removeSpriteFramesFromTexture(Texture2D* texture)
257265
{
258-
std::vector<std::string_view> keysToRemove;
266+
std::vector<uint64_t> keysToRemove;
259267

260268
for (auto&& iter : getSpriteFrames())
261269
{
@@ -282,19 +290,18 @@ SpriteFrame* SpriteFrameCache::getSpriteFrameByName(std::string_view name)
282290
bool SpriteFrameCache::reloadTexture(std::string_view spriteSheetFileName)
283291
{
284292
AXASSERT(!spriteSheetFileName.empty(), "plist filename should not be nullptr");
285-
286-
const auto spriteSheetItr = _spriteSheets.find(spriteSheetFileName);
293+
auto sheetId = computeHash(spriteSheetFileName);
294+
const auto spriteSheetItr = _spriteSheets.find(sheetId);
287295
if (spriteSheetItr == _spriteSheets.end())
288296
{
289297
return false; // Sprite sheet wasn't loaded, so don't reload it
290298
}
291299

292300
const auto format = spriteSheetItr->second->format;
293301

294-
if (isSpriteSheetInUse(spriteSheetFileName))
302+
if (isSpriteSheetInUse(sheetId))
295303
{
296-
removeSpriteSheet(
297-
spriteSheetFileName); // we've removed the associated entry, so spriteSheetItr is no longer valid
304+
removeSpriteSheet(sheetId); // we've removed the associated entry, so spriteSheetItr is no longer valid
298305
}
299306
else
300307
{
@@ -314,28 +321,35 @@ void SpriteFrameCache::insertFrame(const std::shared_ptr<SpriteSheet>& spriteShe
314321
std::string_view frameName,
315322
SpriteFrame* spriteFrame)
316323
{
317-
spriteSheet->frames.emplace(frameName);
318-
_spriteFrames.insert(frameName, spriteFrame); // add SpriteFrame
319-
_spriteSheets[spriteSheet->path] = spriteSheet;
320-
hlookup::set_item(_spriteFrameToSpriteSheetMap, frameName,
321-
spriteSheet); // _spriteFrameToSpriteSheetMap[frameName] = spriteSheet; // insert
322-
// index frameName->plist
324+
auto frameId = computeHash(frameName);
325+
spriteFrame->setName(frameName);
326+
spriteSheet->frames.emplace(frameId);
327+
_spriteFrames.insert(frameId, spriteFrame); // add SpriteFrame
328+
if (spriteSheet->pathId == (uint64_t)-1)
329+
spriteSheet->pathId = computeHash(spriteSheet->path);
330+
hlookup::set_item(_spriteSheets, spriteSheet->pathId, spriteSheet);
331+
hlookup::set_item(_spriteFrameToSpriteSheetMap, frameId, spriteSheet);
323332
}
324333

325334
bool SpriteFrameCache::eraseFrame(std::string_view frameName)
335+
{
336+
return eraseFrame(computeHash(frameName));
337+
}
338+
339+
bool SpriteFrameCache::eraseFrame(uint64_t frameId)
326340
{
327341
// drop SpriteFrame
328-
const auto itFrame = _spriteFrameToSpriteSheetMap.find(frameName);
329-
bool found = itFrame != _spriteFrameToSpriteSheetMap.end();
342+
const auto itFrame = _spriteFrameToSpriteSheetMap.find(frameId);
343+
bool found = itFrame != _spriteFrameToSpriteSheetMap.end();
330344
if (found)
331345
{
332346
auto& spriteSheet = itFrame->second;
333347
spriteSheet->full = false;
334-
spriteSheet->frames.erase(frameName);
348+
spriteSheet->frames.erase(frameId);
335349

336350
if (spriteSheet->frames.empty())
337351
{
338-
_spriteSheets.erase(spriteSheet->path);
352+
_spriteSheets.erase(computeHash(spriteSheet->path));
339353
}
340354

341355
_spriteFrameToSpriteSheetMap.erase(itFrame); // update index frame->plist
@@ -346,11 +360,11 @@ bool SpriteFrameCache::eraseFrame(std::string_view frameName)
346360
// _spriteSheets.clear();
347361
//}
348362
}
349-
_spriteFrames.erase(frameName);
363+
_spriteFrames.erase(frameId);
350364
return found;
351365
}
352366

353-
bool SpriteFrameCache::eraseFrames(const std::vector<std::string_view>& frames)
367+
bool SpriteFrameCache::eraseFrames(const std::vector<uint64_t>& frames)
354368
{
355369
auto ret = false;
356370
for (const auto& frame : frames)
@@ -361,9 +375,9 @@ bool SpriteFrameCache::eraseFrames(const std::vector<std::string_view>& frames)
361375
return ret;
362376
}
363377

364-
bool SpriteFrameCache::removeSpriteSheet(std::string_view spriteSheetFileName)
378+
bool SpriteFrameCache::removeSpriteSheet(uint64_t sheetId)
365379
{
366-
auto it = _spriteSheets.find(spriteSheetFileName);
380+
auto it = _spriteSheets.find(sheetId);
367381
if (it == _spriteSheets.end())
368382
return false;
369383

@@ -375,7 +389,7 @@ bool SpriteFrameCache::removeSpriteSheet(std::string_view spriteSheetFileName)
375389
_spriteFrames.erase(f);
376390
_spriteFrameToSpriteSheetMap.erase(f); // erase plist frame frameName->plist
377391
}
378-
_spriteSheets.erase(spriteSheetFileName); // update index plist->[frameNames]
392+
_spriteSheets.erase(sheetId); // update index plist->[frameNames]
379393

380394
return true;
381395
}
@@ -387,40 +401,28 @@ void SpriteFrameCache::clear()
387401
_spriteFrames.clear();
388402
}
389403

390-
bool SpriteFrameCache::hasFrame(std::string_view frame) const
404+
bool SpriteFrameCache::isSpriteSheetInUse(uint64_t sheetId) const
391405
{
392-
return _spriteFrameToSpriteSheetMap.find(frame) != _spriteFrameToSpriteSheetMap.end();
393-
}
394-
395-
bool SpriteFrameCache::isSpriteSheetInUse(std::string_view spriteSheetFileName) const
396-
{
397-
const auto spriteSheetItr = _spriteSheets.find(spriteSheetFileName);
406+
const auto spriteSheetItr = _spriteSheets.find(sheetId);
398407
return spriteSheetItr != _spriteSheets.end() && !spriteSheetItr->second->frames.empty();
399408
}
400409

401410
SpriteFrame* SpriteFrameCache::findFrame(std::string_view frame)
402411
{
403-
return _spriteFrames.at(frame);
412+
return _spriteFrames.at(computeHash(frame));
404413
}
405414

406-
std::string_view SpriteFrameCache::getSpriteFrameName(SpriteFrame* frame)
415+
SpriteFrame* SpriteFrameCache::findFrame(uint64_t frameId)
407416
{
408-
for (auto& it : _spriteFrames)
409-
{
410-
if (it.second == frame)
411-
{
412-
return it.first;
413-
}
414-
}
415-
return "";
417+
return _spriteFrames.at(frameId);
416418
}
417419

418420
void SpriteFrameCache::addSpriteFrameCapInset(SpriteFrame* spriteFrame, const Rect& capInsets, Texture2D* texture)
419421
{
420422
texture->addSpriteFrameCapInset(spriteFrame, capInsets);
421423
}
422424

423-
StringMap<SpriteFrame*>& SpriteFrameCache::getSpriteFrames()
425+
const ax::Map<uint64_t, SpriteFrame*>& SpriteFrameCache::getSpriteFrames()
424426
{
425427
return _spriteFrames;
426428
}
@@ -457,4 +459,4 @@ ISpriteSheetLoader* SpriteFrameCache::getSpriteSheetLoader(uint32_t spriteSheetF
457459
return nullptr;
458460
}
459461

460-
}
462+
} // namespace ax

core/2d/SpriteFrameCache.h

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,8 @@ class AX_DLL SpriteFrameCache
249249

250250
SpriteFrame* findFrame(std::string_view frame);
251251

252-
std::string_view getSpriteFrameName(SpriteFrame* frame);
252+
// @DEPRECATED, use frame->getName() instead
253+
std::string_view getSpriteFrameName(SpriteFrame* frame) { return frame->getName(); }
253254

254255
/** Record SpriteFrame with plist and frame name, add frame name
255256
* and plist to index
@@ -261,7 +262,7 @@ class AX_DLL SpriteFrameCache
261262
/** Delete frame from cache, rebuild index
262263
*/
263264
bool eraseFrame(std::string_view frameName);
264-
265+
265266
void addSpriteFrameCapInset(SpriteFrame* spriteFrame, const Rect& capInsets, Texture2D* texture);
266267

267268
void registerSpriteSheetLoader(std::shared_ptr<ISpriteSheetLoader> loader);
@@ -273,45 +274,47 @@ class AX_DLL SpriteFrameCache
273274
// MARMALADE: Made this protected not private, as deriving from this class is pretty useful
274275
SpriteFrameCache() {}
275276

277+
SpriteFrame* findFrame(uint64_t frameId);
278+
bool eraseFrame(uint64_t frameId);
279+
276280
/** Removes multiple Sprite Frames from Dictionary.
277281
* @since v0.99.5
278282
*/
279283
void removeSpriteFramesFromDictionary(ValueMap& dictionary);
280284

281285
/** Delete a list of frames from cache, rebuild index
282286
*/
283-
bool eraseFrames(const std::vector<std::string_view>& frame);
287+
bool eraseFrames(const std::vector<uint64_t>& frame);
284288
/** Delete frame from index and SpriteFrame is kept.
285289
*/
286-
bool removeSpriteSheet(std::string_view spriteSheetFileName);
290+
bool removeSpriteSheet(uint64_t sheetId);
287291
/** Clear index and all SpriteFrames.
288292
*/
289293
void clear();
290294

291-
inline bool hasFrame(std::string_view frame) const;
292-
inline bool isSpriteSheetInUse(std::string_view spriteSheetFileName) const;
295+
inline bool isSpriteSheetInUse(uint64_t sheetId) const;
293296

294-
inline StringMap<SpriteFrame*>& getSpriteFrames();
297+
inline const ax::Map<uint64_t, SpriteFrame*>& getSpriteFrames();
295298

296-
void markPlistFull(std::string_view spriteSheetFileName, bool full)
299+
void markPlistFull(uint64_t sheetId, bool full)
297300
{
298301
// _spriteSheets[spriteSheetFileName]->full = full;
299-
auto it = _spriteSheets.find(spriteSheetFileName);
302+
auto it = _spriteSheets.find(sheetId);
300303
if (it != _spriteSheets.end())
301304
{
302305
it.value()->full = full;
303306
}
304307
}
305-
bool isPlistFull(std::string_view spriteSheetFileName) const
308+
bool isPlistFull(uint64_t sheetId) const
306309
{
307-
auto it = _spriteSheets.find(spriteSheetFileName);
308-
return it == _spriteSheets.end() ? false : it->second->full;
310+
auto it = _spriteSheets.find(sheetId);
311+
return it != _spriteSheets.end() && it->second->full;
309312
}
310313

311314
private:
312-
StringMap<SpriteFrame*> _spriteFrames;
313-
hlookup::string_map<std::shared_ptr<SpriteSheet>> _spriteSheets;
314-
hlookup::string_map<std::shared_ptr<SpriteSheet>> _spriteFrameToSpriteSheetMap;
315+
ax::Map<uint64_t, SpriteFrame*> _spriteFrames;
316+
tsl::robin_map<uint64_t, std::shared_ptr<SpriteSheet>> _spriteSheets;
317+
tsl::robin_map<uint64_t, std::shared_ptr<SpriteSheet>> _spriteFrameToSpriteSheetMap;
315318

316319
std::map<uint32_t, std::shared_ptr<ISpriteSheetLoader>> _spriteSheetLoaders;
317320
};

0 commit comments

Comments
 (0)