Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] Further simplify data-structures and algorithms
Browse files Browse the repository at this point in the history
* Eliminate tileDependencies map in favor of leaning on shared_ptr reference counting
* Combine addGlyphs and getGlyphPositions (needs test update)
  • Loading branch information
jfirebaugh committed Mar 15, 2017
1 parent c921020 commit d3c91db
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 102 deletions.
137 changes: 62 additions & 75 deletions src/mbgl/text/glyph_atlas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,37 +52,34 @@ bool GlyphAtlas::hasGlyphRange(const FontStack& fontStack, const GlyphRange& ran
}

void GlyphAtlas::getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphDependencies) {
// Figure out which glyph ranges need to be fetched
GlyphRangeDependencies missing;
for (const auto& fontStackToGlyphIDs : glyphDependencies) {
auto fontStackEntry = entries.find(fontStackToGlyphIDs.first);
for (auto glyphID : fontStackToGlyphIDs.second) {
auto dependencies = std::make_shared<GlyphDependencies>(std::move(glyphDependencies));

// Figure out which glyph ranges need to be fetched. For each range that does need to
// be fetched, record an entry mapping the requestor to a shared pointer containing the
// dependencies. When the shared pointer becomes unique, we know that all the dependencies
// for that requestor have been fetched, and can notify it of completion.
for (const auto& dependency : *dependencies) {
const FontStack& fontStack = dependency.first;
const GlyphIDs& glyphIDs = dependency.second;

Entry& entry = entries[fontStack];

for (const auto& glyphID : glyphIDs) {
GlyphRange range = getGlyphRange(glyphID);
if (fontStackEntry == entries.end() ||
!rangeIsParsed(fontStackEntry->second.ranges, range)) {
missing[fontStackToGlyphIDs.first].insert(range);
if (!rangeIsParsed(entry.ranges, range)) {
entry.ranges.emplace(std::piecewise_construct,
std::forward_as_tuple(range),
std::forward_as_tuple(this, fontStack, range, this, fileSource));

entry.ranges.find(range)->second.requestors[&requestor] = dependencies;
}
}
}

if (missing.empty()) {
// Send "glyphs available" message immediately to requestor
addGlyphs(requestor, glyphDependencies);
requestor.onGlyphsAvailable(getGlyphPositions(glyphDependencies));
} else {
// Trigger network requests for glyphs, send "glyphs available" message when all requests have finished
tileDependencies.emplace(std::piecewise_construct,
std::forward_as_tuple(&requestor),
std::forward_as_tuple(missing, std::move(glyphDependencies)));
for (auto fontStackToGlyphIDs : missing) {
for (auto& range : fontStackToGlyphIDs.second) {
entries[fontStackToGlyphIDs.first].ranges.emplace(std::piecewise_construct,
std::forward_as_tuple(range),
std::forward_as_tuple(this, fontStackToGlyphIDs.first, range, this, fileSource));

entries[fontStackToGlyphIDs.first].ranges.find(range)->second.addRequestor(requestor);
}
}

// If the shared dependencies pointer is already unique, then all dependent glyph ranges
// have already been loaded. Send a notification immediately.
if (dependencies.unique()) {
addGlyphs(requestor, *dependencies);
}
}

Expand All @@ -97,67 +94,57 @@ void GlyphAtlas::onGlyphsError(const FontStack& fontStack, const GlyphRange& ran
}

void GlyphAtlas::onGlyphsLoaded(const FontStack& fontStack, const GlyphRange& range) {
auto glyphPBF = entries[fontStack].ranges.find(range);
if (glyphPBF != entries[fontStack].ranges.end()) {
auto glyphRequestors = glyphPBF->second.processRequestors();
for (auto requestor : glyphRequestors) {
auto tileDependency = tileDependencies.find(requestor);
if (tileDependency != tileDependencies.end()) {
auto fontRanges = tileDependency->second.pendingRanges.find(fontStack);
if (fontRanges != tileDependency->second.pendingRanges.end()) {
fontRanges->second.erase(range);
if (fontRanges->second.empty()) {
tileDependency->second.pendingRanges.erase(fontRanges);
}
}
if (tileDependency->second.pendingRanges.empty()) {
addGlyphs(*requestor, tileDependency->second.glyphDependencies);
tileDependency->first->onGlyphsAvailable(getGlyphPositions(tileDependency->second.glyphDependencies));
tileDependencies.erase(requestor);
}
Entry& entry = entries[fontStack];

auto it = entry.ranges.find(range);
if (it != entry.ranges.end()) {
for (auto& pair : it->second.requestors) {
GlyphRequestor& requestor = *pair.first;
const std::shared_ptr<GlyphDependencies>& dependencies = pair.second;
if (dependencies.unique()) {
addGlyphs(requestor, *dependencies);
}
}
it->second.requestors.clear();
}

if (observer) {
observer->onGlyphsLoaded(fontStack, range);
}
}


// Builds up the set of glyph positions needed for a given tile; result is handed to worker threads
GlyphPositionMap GlyphAtlas::getGlyphPositions(const GlyphDependencies& glyphDependencies) const {
void GlyphAtlas::addGlyphs(GlyphRequestor& requestor, const GlyphDependencies& glyphDependencies) {
GlyphPositionMap glyphPositions;

for (const auto& fontStackToGlyphIDs : glyphDependencies) {
auto entry = entries.find(fontStackToGlyphIDs.first);
if (entry != entries.end()) {

for (GlyphID glyphID : fontStackToGlyphIDs.second) {
auto sdf = entry->second.glyphSet.getSDFs().find(glyphID);
if (sdf != entry->second.glyphSet.getSDFs().end()) {
auto glyphRect = entry->second.glyphValues.find(glyphID);
// It's possible to have an SDF without a valid position (if the SDF was malformed). We indicate this case with Rect<uint16_t>(0,0,0,0).
const Rect<uint16_t> rect = glyphRect == entry->second.glyphValues.end() ? Rect<uint16_t>(0,0,0,0) : glyphRect->second.rect;
glyphPositions[fontStackToGlyphIDs.first].emplace(std::piecewise_construct,
std::forward_as_tuple(glyphID),
std::forward_as_tuple(rect, sdf->second.metrics));
}
}
}
}
return glyphPositions;
}

void GlyphAtlas::addGlyphs(GlyphRequestor& requestor, const GlyphDependencies &glyphDependencies) {
for (const auto& fontStackToGlyphIDs : glyphDependencies) {
const auto& sdfs = getGlyphSet(fontStackToGlyphIDs.first).getSDFs();
for (auto glyphID : fontStackToGlyphIDs.second) {
for (const auto& dependency : glyphDependencies) {
const FontStack& fontStack = dependency.first;
const GlyphIDs& glyphIDs = dependency.second;

GlyphPositions& positions = glyphPositions[fontStack];
Entry& entry = entries[fontStack];
const auto& sdfs = entry.glyphSet.getSDFs();

for (const auto& glyphID : glyphIDs) {
auto it = sdfs.find(glyphID);
if (it != sdfs.end()) { // If we got the range, but still didn't get a glyph, go ahead with rendering
addGlyph(requestor, fontStackToGlyphIDs.first, it->second);
}
if (it == sdfs.end())
continue;

addGlyph(requestor, fontStack, it->second);

// It's possible to have an SDF without a valid position (if the SDF was malformed).
// We indicate this case with Rect<uint16_t>(0,0,0,0).
auto glyphRect = entry.glyphValues.find(glyphID);
const Rect<uint16_t> rect = glyphRect == entry.glyphValues.end()
? Rect<uint16_t>(0,0,0,0)
: glyphRect->second.rect;

positions.emplace(std::piecewise_construct,
std::forward_as_tuple(glyphID),
std::forward_as_tuple(rect, it->second.metrics));
}
}

requestor.onGlyphsAvailable(glyphPositions);
}

void GlyphAtlas::addGlyph(GlyphRequestor& requestor,
Expand Down
19 changes: 5 additions & 14 deletions src/mbgl/text/glyph_atlas.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class GlyphAtlas : public util::noncopyable, public GlyphAtlasObserver {
// locally available, the observer will be notified that the glyphs are available
// immediately. Otherwise, a request on the FileSource is made, and when all glyphs
// are parsed and added to the atlas, the observer will be notified.
// Workers are given a copied 'GlyphPositions' map to use for placing their glyphs.
// The positions specified in this object are guaranteed to be
// valid for the lifetime of the tile.
void getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphs);

void setURL(const std::string &url) {
Expand Down Expand Up @@ -73,13 +76,10 @@ class GlyphAtlas : public util::noncopyable, public GlyphAtlasObserver {
virtual void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr);

friend class ::GlyphAtlasTest;

private:
void addGlyphs(GlyphRequestor& requestor, const GlyphDependencies& glyphDependencies);
// Workers are given a copied 'GlyphPositions' map to use for placing their glyphs.
// The positions specified in this object are guaranteed to be
// valid for the lifetime of the tile.
GlyphPositionMap getGlyphPositions(const GlyphDependencies& glyphs) const;


// Only used by GlyphAtlasTest
bool hasGlyphRanges(const FontStack&, const GlyphRangeSet& ranges) const;
bool hasGlyphRange(const FontStack&, const GlyphRange& range) const;
Expand All @@ -103,15 +103,6 @@ class GlyphAtlas : public util::noncopyable, public GlyphAtlasObserver {
};

std::unordered_map<FontStack, Entry, FontStackHash> entries;

struct TileDependency {
TileDependency(const GlyphRangeDependencies& _pendingRanges, GlyphDependencies _glyphDependencies)
: pendingRanges(_pendingRanges), glyphDependencies(std::move(_glyphDependencies))
{}
GlyphRangeDependencies pendingRanges;
GlyphDependencies glyphDependencies;
};
std::unordered_map<GlyphRequestor*,TileDependency> tileDependencies;

GlyphAtlasObserver* observer = nullptr;

Expand Down
8 changes: 0 additions & 8 deletions src/mbgl/text/glyph_pbf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,4 @@ GlyphPBF::GlyphPBF(GlyphAtlas* atlas,

GlyphPBF::~GlyphPBF() = default;

void GlyphPBF::addRequestor(GlyphRequestor& requestor) {
requestors.insert(&requestor);
}

std::set<GlyphRequestor*> GlyphPBF::processRequestors() {
return std::move(requestors);
}

} // namespace mbgl
7 changes: 2 additions & 5 deletions src/mbgl/text/glyph_pbf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <functional>
#include <string>
#include <memory>
#include <unordered_map>

namespace mbgl {

Expand All @@ -26,18 +27,14 @@ class GlyphPBF : private util::noncopyable {
FileSource&);
~GlyphPBF();

void addRequestor(GlyphRequestor&);
std::set<GlyphRequestor*> processRequestors();

bool isParsed() const {
return parsed;
}

private:
bool parsed;
std::unique_ptr<AsyncRequest> req;
GlyphAtlasObserver* observer = nullptr;
std::set<GlyphRequestor*> requestors;
std::unordered_map<GlyphRequestor*, std::shared_ptr<GlyphDependencies>> requestors;
};

} // namespace mbgl

0 comments on commit d3c91db

Please sign in to comment.