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

raster performance improvements #114

Closed
wants to merge 8 commits into from
5 changes: 4 additions & 1 deletion include/llmr/map/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

#include <cstdint>
#include <string>
#include <map>
#include <functional>

namespace llmr {

Expand Down Expand Up @@ -63,6 +65,7 @@ class Map : private util::noncopyable {
void stopRotating();

void toggleDebug();
void logTileKeys();

private:
bool findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::forward_list<Tile::ID>& retain);
Expand All @@ -88,7 +91,7 @@ class Map : private util::noncopyable {

bool use_raster = false;

std::forward_list<Tile> tiles;
std::map<uint8_t, std::forward_list<Tile>, std::greater<uint8_t>> tiles;
std::forward_list<std::weak_ptr<TileData>> tile_data;
};

Expand Down
2 changes: 1 addition & 1 deletion include/llmr/renderer/painter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Painter : private util::noncopyable {
void setup();
void clear();
void changeMatrix();
void render(const Tile& tile);
void render(const Tile& tile, const uint8_t raster_tile_count = 0);
void renderMatte();
void renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id);
void renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id);
Expand Down
138 changes: 97 additions & 41 deletions src/map/map.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <llmr/map/map.hpp>
#include <llmr/map/settings.hpp>
#include <llmr/platform/platform.hpp>
#include <llmr/util/constants.hpp>
#include <llmr/style/resources.hpp>
#include <llmr/style/sprite.hpp>
#include <llmr/map/coverage.hpp>
Expand Down Expand Up @@ -244,11 +245,27 @@ void Map::update() {
platform::restart();
}

void Map::logTileKeys() {
fprintf(stderr, "tile keys: ");
for (const auto& tile_pair : tiles) {
const uint8_t& zoom = tile_pair.first;
fprintf(stderr, "%d ", zoom);
}
fprintf(stderr, "\n");
}

TileData::State Map::hasTile(const Tile::ID& id) {
for (const Tile& tile : tiles) {
if (tile.id == id && tile.data) {
return tile.data->state;
for (const auto& tile_pair : tiles) {
const uint8_t& zoom = tile_pair.first;
const std::forward_list<Tile>& zoom_tiles = tile_pair.second;
if (zoom == id.z) {
auto tile_it = std::find_if(zoom_tiles.begin(), zoom_tiles.end(), [&id](const Tile& tile) {
return tile.id == id && tile.data;
});
if (tile_it != zoom_tiles.end()) {
return tile_it->data->state;
}
break;
}
}

Expand All @@ -262,8 +279,26 @@ TileData::State Map::addTile(const Tile::ID& id) {
return state;
}

tiles.emplace_front(id);
Tile& new_tile = tiles.front();
bool zoom_mapped = false;

for (auto& tile_pair : tiles) {
const uint8_t& zoom = tile_pair.first;
std::forward_list<Tile>& zoom_tiles = tile_pair.second;
if (zoom == id.z) {
zoom_tiles.emplace_front(id);
zoom_mapped = true;
break;
}
}

if (!zoom_mapped) {
tiles.emplace(std::make_pair(id.z, std::forward_list<Tile> ()));
auto zoom_tiles_it = tiles.find(id.z);
zoom_tiles_it->second.emplace_front(id);
}

auto zoom_tiles_it = tiles.find(id.z);
Tile& new_tile = zoom_tiles_it->second.front();

// We couldn't find the tile in the list. Create a new one.
// Try to find the associated TileData object.
Expand Down Expand Up @@ -344,7 +379,6 @@ bool Map::findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::for
return false;
}


bool Map::updateTiles() {
bool changed = false;

Expand Down Expand Up @@ -373,14 +407,13 @@ bool Map::updateTiles() {
// parent or child tiles that are *already* loaded.
std::forward_list<Tile::ID> retain(required);

// Add existing child/parent tiles if the actual tile is not yet loaded
// Add existing child/parent tiles if the actual tile is not yet loaded.
// Tiles are auto-sorted in the map by highest zoom front to back so that
// we draw more detailed tiles first.
for (const Tile::ID& id : required) {
const TileData::State state = addTile(id);

if (state != TileData::State::parsed) {
if (use_raster && (transform.rotating || transform.scaling || transform.panning))
break;

// The tile we require is not yet loaded. Try to find a parent or
// child tile that we already have.

Expand All @@ -403,22 +436,19 @@ bool Map::updateTiles() {
// Remove tiles that we definitely don't need, i.e. tiles that are not on
// the required list.
std::forward_list<Tile::ID> retain_data;
tiles.remove_if([&retain, &retain_data, &changed](const Tile & tile) {
bool obsolete = std::find(retain.begin(), retain.end(), tile.id) == retain.end();
if (obsolete) {
changed = true;
} else {
retain_data.push_front(tile.data->id);
}
return obsolete;
});

// Sort tiles by zoom level, front to back.
// We're painting front-to-back, so we want to draw more detailed tiles first
// before filling in other parts with lower zoom levels.
tiles.sort([](const Tile & a, const Tile & b) {
return a.id.z > b.id.z;
});
for (auto& tile_pair : tiles) {
std::forward_list<Tile>& zoom_tiles = tile_pair.second;
zoom_tiles.remove_if([&retain, &retain_data, &changed](const Tile& tile) {
bool obsolete = std::find(retain.begin(), retain.end(), tile.id) == retain.end();
if (obsolete) {
changed = true;
} else {
retain_data.push_front(tile.data->id);
}
return obsolete;
});
}

// Remove all the expired pointers from the list.
tile_data.remove_if([&retain_data](const std::weak_ptr<TileData>& tile_data) {
Expand Down Expand Up @@ -457,27 +487,53 @@ bool Map::render() {
// the stencil buffer.
uint8_t i = 1;
painter.prepareClippingMask();
for (Tile& tile : tiles) {
if (tile.data && tile.data->state == TileData::State::parsed) {
// The position matrix.
transform.matrixFor(tile.matrix, tile.id);
matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix);
tile.clip_id = i++;
painter.drawClippingMask(tile.matrix, tile.clip_id, !tile.data->use_raster);

for (auto& tile_pair : tiles) {
std::forward_list<Tile>& zoom_tiles = tile_pair.second;
for (Tile& tile : zoom_tiles) {
if (tile.data && tile.data->state == TileData::State::parsed) {
// The position matrix.
transform.matrixFor(tile.matrix, tile.id);
matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix);
tile.clip_id = i++;
painter.drawClippingMask(tile.matrix, tile.clip_id, !tile.data->use_raster);
}
}
}
painter.finishClippingMask();

for (const Tile& tile : tiles) {
if (tile.data && tile.data->state == TileData::State::parsed) {
if (tile.data->use_raster && *tile.data->raster && !tile.data->raster->textured) {
tile.data->raster->setTexturepool(&texturepool);
tile.data->raster->beginFadeInAnimation();
}
if (tile.data->use_raster && tile.data->raster->needsAnimation()) {
tile.data->raster->updateAnimations();
// reuse clip_id/count for raster depth
uint8_t raster_tile_count = i;
int32_t adjusted_zoom;

for (auto& tile_pair : tiles) {
std::forward_list<Tile>& zoom_tiles = tile_pair.second;
for (Tile& tile : zoom_tiles) {
if (tile.data && tile.data->state == TileData::State::parsed) {
if (tile.data->use_raster && *tile.data->raster && !tile.data->raster->textured) {
tile.data->raster->setTexturepool(&texturepool);

// determine effective raster/retina zoom
adjusted_zoom = transform.getIntegerZoom();
adjusted_zoom += (uint32_t)((llmr::util::tileSize / 256.0f) - 1.0f);
if (pixel_ratio > 1.0) {
adjusted_zoom++;
}

// don't fade parent/child tiles
if (tile.id.z != adjusted_zoom) {
tile.data->raster->opacity = 1.0;
}
else {
tile.data->raster->beginFadeInAnimation();
}
}
if (tile.data->use_raster && tile.data->raster->needsAnimation()) {
tile.data->raster->updateAnimations();
}

painter.render(tile, (use_raster ? raster_tile_count : 0));
}
painter.render(tile);
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/renderer/painter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ void Painter::clear() {
#endif
}

void Painter::render(const Tile& tile) {
void Painter::render(const Tile& tile, const uint8_t raster_tile_count) {
assert(tile.data);
if (tile.data->state != TileData::State::parsed) {
return;
Expand All @@ -163,6 +163,9 @@ void Painter::render(const Tile& tile) {
glStencilFunc(GL_EQUAL, tile.clip_id, 0xFF);

if (tile.data->use_raster) {
assert(raster_tile_count);
float strata_thickness = 1.0f / (raster_tile_count + 1);
strata = tile.clip_id * strata_thickness;
renderRaster(tile.data);
} else {
renderLayers(tile.data, style.layers);
Expand Down
14 changes: 6 additions & 8 deletions src/util/texturepool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,27 @@ GLuint Texturepool::getTextureID() {
}

void Texturepool::removeTextureID(GLuint texture_id) {
bool needs_clear = false;

glBindTexture(GL_TEXTURE_2D, texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);

texture_ids.insert(texture_id);

if (texture_ids.size() > TextureMax)
needs_clear = true;

if (needs_clear)
if (texture_ids.size() > TextureMax) {
clearTextureIDs();
}
}

void Texturepool::clearTextureIDs() {
std::vector<GLuint> ids_to_remove;
ids_to_remove.reserve(texture_ids.size());

for (std::set<GLuint>::iterator id_iterator = texture_ids.begin(); id_iterator != texture_ids.end(); ++id_iterator)
for (std::set<GLuint>::iterator id_iterator = texture_ids.begin(); id_iterator != texture_ids.end(); ++id_iterator) {
ids_to_remove.push_back(*id_iterator);
}

if (!ids_to_remove.empty())
if (!ids_to_remove.empty()) {
glDeleteTextures((GLsizei)ids_to_remove.size(), &ids_to_remove[0]);
}

texture_ids.clear();
}