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

Commit

Permalink
add onStyleImageMissing to allow dynamically loaded or generated imag…
Browse files Browse the repository at this point in the history
…es (#14253)

Also make `Style#updateImage(...)` much faster when the image doesn't change size. This can be useful for asynchronously generating images.
  • Loading branch information
ansis authored Apr 2, 2019
1 parent 805b140 commit 2455275
Show file tree
Hide file tree
Showing 25 changed files with 280 additions and 37 deletions.
2 changes: 2 additions & 0 deletions include/mbgl/map/map_observer.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <mbgl/style/source.hpp>
#include <mbgl/style/image.hpp>

#include <cstdint>
#include <string>
Expand Down Expand Up @@ -46,6 +47,7 @@ class MapObserver {
virtual void onDidFinishLoadingStyle() {}
virtual void onSourceChanged(style::Source&) {}
virtual void onDidBecomeIdle() {}
virtual void onStyleImageMissing(const std::string&) {}
};

} // namespace mbgl
4 changes: 4 additions & 0 deletions include/mbgl/renderer/renderer_observer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class RendererObserver {

// Final frame
virtual void onDidFinishRenderingMap() {}

// Style is missing an image
using StyleImageMissingCallback = std::function<void()>;
virtual void onStyleImageMissing(const std::string&, StyleImageMissingCallback done) { done(); }
};

} // namespace mbgl
7 changes: 6 additions & 1 deletion platform/darwin/src/MGLRendererFrontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ class MGLRenderFrontend : public mbgl::RendererFrontend

mbgl::BackendScope guard { mbglBackend, mbgl::BackendScope::ScopeType::Implicit };

renderer->render(*updateParameters);
// onStyleImageMissing might be called during a render. The user implemented method
// could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`.
// Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is
// still using them.
auto updateParameters_ = updateParameters;
renderer->render(*updateParameters_);
}

mbgl::Renderer* getRenderer() {
Expand Down
8 changes: 7 additions & 1 deletion platform/default/src/mbgl/gl/headless_frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ HeadlessFrontend::HeadlessFrontend(Size size_, float pixelRatio_, Scheduler& sch
asyncInvalidate([this] {
if (renderer && updateParameters) {
mbgl::BackendScope guard { backend };
renderer->render(*updateParameters);

// onStyleImageMissing might be called during a render. The user implemented method
// could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`.
// Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is
// still using them.
auto updateParameters_ = updateParameters;
renderer->render(*updateParameters_);
}
}),
renderer(std::make_unique<Renderer>(backend, pixelRatio, scheduler, mode, programCacheDir, localFontFamily)) {
Expand Down
7 changes: 6 additions & 1 deletion platform/glfw/glfw_renderer_frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ void GLFWRendererFrontend::render() {

mbgl::BackendScope guard { glfwView, mbgl::BackendScope::ScopeType::Implicit };

renderer->render(*updateParameters);
// onStyleImageMissing might be called during a render. The user implemented method
// could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`.
// Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is
// still using them.
auto updateParameters_ = updateParameters;
renderer->render(*updateParameters_);
}

mbgl::Renderer* GLFWRendererFrontend::getRenderer() {
Expand Down
1 change: 1 addition & 0 deletions src/core-files.json
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@
"mbgl/renderer/group_by_layout.hpp": "src/mbgl/renderer/group_by_layout.hpp",
"mbgl/renderer/image_atlas.hpp": "src/mbgl/renderer/image_atlas.hpp",
"mbgl/renderer/image_manager.hpp": "src/mbgl/renderer/image_manager.hpp",
"mbgl/renderer/image_manager_observer.hpp": "src/mbgl/renderer/image_manager_observer.hpp",
"mbgl/renderer/layers/render_background_layer.hpp": "src/mbgl/renderer/layers/render_background_layer.hpp",
"mbgl/renderer/layers/render_circle_layer.hpp": "src/mbgl/renderer/layers/render_circle_layer.hpp",
"mbgl/renderer/layers/render_custom_layer.hpp": "src/mbgl/renderer/layers/render_custom_layer.hpp",
Expand Down
14 changes: 14 additions & 0 deletions src/mbgl/gfx/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,25 @@ class Context {
texture.size = image.size;
}

template <typename Image>
void updateTextureSub(Texture& texture,
const Image& image,
const uint16_t offsetX,
const uint16_t offsetY,
TextureChannelDataType type = TextureChannelDataType::UnsignedByte) {
assert(image.size.width + offsetX <= texture.size.width);
assert(image.size.height + offsetY <= texture.size.height);
auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
updateTextureResourceSub(*texture.resource, offsetX, offsetY, image.size, image.data.get(), format, type);
}

protected:
virtual std::unique_ptr<TextureResource> createTextureResource(
Size, const void* data, TexturePixelType, TextureChannelDataType) = 0;
virtual void updateTextureResource(const TextureResource&, Size, const void* data,
TexturePixelType, TextureChannelDataType) = 0;
virtual void updateTextureResourceSub(const TextureResource&, uint16_t xOffset, uint16_t yOffset, Size, const void* data,
TexturePixelType, TextureChannelDataType) = 0;

public:
DrawScope createDrawScope() {
Expand Down
18 changes: 18 additions & 0 deletions src/mbgl/gl/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,24 @@ void Context::updateTextureResource(const gfx::TextureResource& resource,
Enum<gfx::TextureChannelDataType>::to(type), data));
}

void Context::updateTextureResourceSub(const gfx::TextureResource& resource,
const uint16_t xOffset,
const uint16_t yOffset,
const Size size,
const void* data,
gfx::TexturePixelType format,
gfx::TextureChannelDataType type) {
// Always use texture unit 0 for manipulating it.
activeTextureUnit = 0;
texture[0] = static_cast<const gl::TextureResource&>(resource).texture;
MBGL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0,
xOffset, yOffset,
size.width, size.height,
Enum<gfx::TexturePixelType>::to(format),
Enum<gfx::TextureChannelDataType>::to(type), data));
}


std::unique_ptr<gfx::DrawScopeResource> Context::createDrawScopeResource() {
return std::make_unique<gl::DrawScopeResource>(createVertexArray());
}
Expand Down
1 change: 1 addition & 0 deletions src/mbgl/gl/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ class Context final : public gfx::Context {

std::unique_ptr<gfx::TextureResource> createTextureResource(Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override;
void updateTextureResource(const gfx::TextureResource&, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override;
void updateTextureResourceSub(const gfx::TextureResource&, const uint16_t xOffset, const uint16_t yOffset, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override;

std::unique_ptr<gfx::DrawScopeResource> createDrawScopeResource() override;

Expand Down
10 changes: 10 additions & 0 deletions src/mbgl/map/map_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,14 @@ void Map::Impl::jumpTo(const CameraOptions& camera) {
onUpdate();
}

void Map::Impl::onStyleImageMissing(const std::string& id, std::function<void()> done) {

if (style->getImage(id) == nullptr) {
observer.onStyleImageMissing(id);
}

done();
onUpdate();
}

} // namespace mbgl
1 change: 1 addition & 0 deletions src/mbgl/map/map_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class Map::Impl : public style::Observer, public RendererObserver {
void onDidFinishRenderingFrame(RenderMode, bool) final;
void onWillStartRenderingMap() final;
void onDidFinishRenderingMap() final;
void onStyleImageMissing(const std::string&, std::function<void()>) final;

// Map
void jumpTo(const CameraOptions&);
Expand Down
40 changes: 35 additions & 5 deletions src/mbgl/renderer/image_atlas.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
#include <mbgl/renderer/image_atlas.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/renderer/image_manager.hpp>

#include <mapbox/shelf-pack.hpp>

namespace mbgl {

static constexpr uint32_t padding = 1;

ImagePosition::ImagePosition(const mapbox::Bin& bin, const style::Image::Impl& image)
ImagePosition::ImagePosition(const mapbox::Bin& bin, const style::Image::Impl& image, uint32_t version_)
: pixelRatio(image.pixelRatio),
textureRect(
bin.x + padding,
bin.y + padding,
bin.w - padding * 2,
bin.h - padding * 2
) {
),
version(version_) {
}

const mapbox::Bin& _packImage(mapbox::ShelfPack& pack, const style::Image::Impl& image, ImageAtlas& resultImage, ImageType imageType) {
Expand Down Expand Up @@ -49,7 +52,30 @@ const mapbox::Bin& _packImage(mapbox::ShelfPack& pack, const style::Image::Impl&
return bin;
}

ImageAtlas makeImageAtlas(const ImageMap& icons, const ImageMap& patterns) {
void ImageAtlas::patchUpdatedImages(gfx::Context& context, gfx::Texture& atlasTexture, const ImageManager& imageManager) {
for (auto& updatedImageVersion : imageManager.updatedImageVersions) {
auto iconPosition = iconPositions.find(updatedImageVersion.first);
if (iconPosition != iconPositions.end()) {
patchUpdatedImage(context, atlasTexture, iconPosition->second, imageManager, updatedImageVersion.first, updatedImageVersion.second);
}
auto patternPosition = patternPositions.find(updatedImageVersion.first);
if (patternPosition != patternPositions.end()) {
patchUpdatedImage(context, atlasTexture, patternPosition->second, imageManager, updatedImageVersion.first, updatedImageVersion.second);
}
}
}

void ImageAtlas::patchUpdatedImage(gfx::Context& context, gfx::Texture& atlasTexture, ImagePosition& position, const ImageManager& imageManager, const std::string& name, uint16_t version) {
if (position.version == version) return;

auto updatedImage = imageManager.getImage(name);
if (updatedImage == nullptr) return;

context.updateTextureSub(atlasTexture, updatedImage->image, position.textureRect.x, position.textureRect.y);
position.version = version;
}

ImageAtlas makeImageAtlas(const ImageMap& icons, const ImageMap& patterns, const std::unordered_map<std::string, uint32_t>& versionMap) {
ImageAtlas result;

mapbox::ShelfPack::ShelfPackOptions options;
Expand All @@ -59,13 +85,17 @@ ImageAtlas makeImageAtlas(const ImageMap& icons, const ImageMap& patterns) {
for (const auto& entry : icons) {
const style::Image::Impl& image = *entry.second;
const mapbox::Bin& bin = _packImage(pack, image, result, ImageType::Icon);
result.iconPositions.emplace(image.id, ImagePosition { bin, image });
auto it = versionMap.find(entry.first);
auto version = it != versionMap.end() ? it->second : 0;
result.iconPositions.emplace(image.id, ImagePosition { bin, image, version });
}

for (const auto& entry : patterns) {
const style::Image::Impl& image = *entry.second;
const mapbox::Bin& bin = _packImage(pack, image, result, ImageType::Pattern);
result.patternPositions.emplace(image.id, ImagePosition { bin, image });
auto it = versionMap.find(entry.first);
auto version = it != versionMap.end() ? it->second : 0;
result.patternPositions.emplace(image.id, ImagePosition { bin, image, version });
}

pack.shrink();
Expand Down
16 changes: 14 additions & 2 deletions src/mbgl/renderer/image_atlas.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@

namespace mbgl {

namespace gfx {
class Texture;
class Context;
} // namespace gfx

class ImageManager;

class ImagePosition {
public:
ImagePosition(const mapbox::Bin&, const style::Image::Impl&);
ImagePosition(const mapbox::Bin&, const style::Image::Impl&, uint32_t version = 0);

float pixelRatio;
Rect<uint16_t> textureRect;
uint32_t version;

std::array<uint16_t, 2> tl() const {
return {{
Expand Down Expand Up @@ -51,8 +59,12 @@ class ImageAtlas {
PremultipliedImage image;
ImagePositions iconPositions;
ImagePositions patternPositions;

void patchUpdatedImages(gfx::Context&, gfx::Texture&, const ImageManager&);
private:
void patchUpdatedImage(gfx::Context&, gfx::Texture&, ImagePosition& position, const ImageManager& imageManager, const std::string& name, uint16_t version);
};

ImageAtlas makeImageAtlas(const ImageMap&, const ImageMap&);
ImageAtlas makeImageAtlas(const ImageMap&, const ImageMap&, const std::unordered_map<std::string, uint32_t>& versionMap);

} // namespace mbgl
Loading

0 comments on commit 2455275

Please sign in to comment.