diff options
Diffstat (limited to 'src/mbgl/renderer/image_manager.cpp')
-rw-r--r-- | src/mbgl/renderer/image_manager.cpp | 100 |
1 files changed, 90 insertions, 10 deletions
diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index 9c9f6c6e08..d2994d6f2d 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -1,9 +1,16 @@ #include <mbgl/renderer/image_manager.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/gfx/context.hpp> +#include <mbgl/renderer/image_manager_observer.hpp> namespace mbgl { +static ImageManagerObserver nullObserver; + +void ImageManager::setObserver(ImageManagerObserver* observer_) { + observer = observer_ ? observer_ : &nullObserver; +} + void ImageManager::setLoaded(bool loaded_) { if (loaded == loaded_) { return; @@ -13,7 +20,7 @@ void ImageManager::setLoaded(bool loaded_) { if (loaded) { for (const auto& entry : requestors) { - notify(*entry.first, entry.second); + checkMissingAndNotify(*entry.first, entry.second); } requestors.clear(); } @@ -28,9 +35,23 @@ void ImageManager::addImage(Immutable<style::Image::Impl> image_) { images.emplace(image_->id, std::move(image_)); } -void ImageManager::updateImage(Immutable<style::Image::Impl> image_) { +bool ImageManager::updateImage(Immutable<style::Image::Impl> image_) { + auto oldImage = images.find(image_->id); + assert(oldImage != images.end()); + if (oldImage == images.end()) return false; + + auto sizeChanged = oldImage->second->image.size != image_->image.size; + + if (sizeChanged) { + updatedImageVersions.erase(image_->id); + } else { + updatedImageVersions[image_->id]++; + } + removeImage(image_->id); addImage(std::move(image_)); + + return sizeChanged; } void ImageManager::removeImage(const std::string& id) { @@ -60,10 +81,15 @@ const style::Image::Impl* ImageManager::getImage(const std::string& id) const { } void ImageManager::getImages(ImageRequestor& requestor, ImageRequestPair&& pair) { - // If the sprite has been loaded, or if all the icon dependencies are already present - // (i.e. if they've been addeded via runtime styling), then notify the requestor immediately. - // Otherwise, delay notification until the sprite is loaded. At that point, if any of the - // dependencies are still unavailable, we'll just assume they are permanently missing. + // remove previous requests from this tile + removeRequestor(requestor); + + // If all the icon dependencies are already present ((i.e. if they've been addeded via + // runtime styling), then notify the requestor immediately. Otherwise, if the + // sprite has not loaded, then wait for it. When the sprite has loaded check + // if all icons are available. If any are missing, call `onStyleImageMissing` + // to give the user a chance to provide the icon. If they are not provided + // by the next frame we'll assume they are permanently missing. bool hasAllDependencies = true; if (!isLoaded()) { for (const auto& dependency : pair.first) { @@ -72,29 +98,83 @@ void ImageManager::getImages(ImageRequestor& requestor, ImageRequestPair&& pair) } } } - if (isLoaded() || hasAllDependencies) { - notify(requestor, std::move(pair)); - } else { + + if (hasAllDependencies) { + notify(requestor, pair); + } else if (!isLoaded()) { requestors.emplace(&requestor, std::move(pair)); + } else { + checkMissingAndNotify(requestor, std::move(pair)); } } void ImageManager::removeRequestor(ImageRequestor& requestor) { requestors.erase(&requestor); + missingImageRequestors.erase(&requestor); +} + +void ImageManager::notifyIfMissingImageAdded() { + for (auto it = missingImageRequestors.begin(); it != missingImageRequestors.end();) { + if (it->second.callbacksRemaining == 0) { + notify(*it->first, it->second.pair); + missingImageRequestors.erase(it++); + } else { + it++; + } + } +} + +void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageRequestPair& pair) { + unsigned int missing = 0; + for (const auto& dependency : pair.first) { + auto it = images.find(dependency.first); + if (it == images.end()) { + missing++; + } + } + + if (missing > 0) { + ImageRequestor* requestorPtr = &requestor; + + missingImageRequestors.emplace(requestorPtr, MissingImageRequestPair { std::move(pair), missing }); + + for (const auto& dependency : pair.first) { + auto it = images.find(dependency.first); + if (it == images.end()) { + assert(observer != nullptr); + observer->onStyleImageMissing(dependency.first, [this, requestorPtr]() { + auto requestorIt = missingImageRequestors.find(requestorPtr); + if (requestorIt != missingImageRequestors.end()) { + assert(requestorIt->second.callbacksRemaining > 0); + requestorIt->second.callbacksRemaining--; + } + }); + } + } + + } else { + notify(requestor, pair); + } } void ImageManager::notify(ImageRequestor& requestor, const ImageRequestPair& pair) const { ImageMap iconMap; ImageMap patternMap; + ImageVersionMap versionMap; for (const auto& dependency : pair.first) { auto it = images.find(dependency.first); if (it != images.end()) { dependency.second == ImageType::Pattern ? patternMap.emplace(*it) : iconMap.emplace(*it); + + auto versionIt = updatedImageVersions.find(dependency.first); + if (versionIt != updatedImageVersions.end()) { + versionMap.emplace(versionIt->first, versionIt->second); + } } } - requestor.onImagesAvailable(iconMap, patternMap, pair.second); + requestor.onImagesAvailable(iconMap, patternMap, std::move(versionMap), pair.second); } void ImageManager::dumpDebugLogs() const { |