summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2016-05-24 16:58:09 +0200
committerKonstantin Käfer <mail@kkaefer.com>2016-05-27 10:15:06 +0200
commit1b8d280e3fff3d9be1631dd960b9f426d329b36c (patch)
treeb56eb79c9df4f79340f12203b6ee8b411721d425
parentebff2234e42df1ad14c5e567f87271bc4d9274b2 (diff)
downloadqtlocation-mapboxgl-1b8d280e3fff3d9be1631dd960b9f426d329b36c.tar.gz
[core] refactor updateRenderables algorithm
-rw-r--r--src/mbgl/algorithm/update_renderables.hpp115
-rw-r--r--src/mbgl/source/source.cpp36
-rw-r--r--test/algorithm/mock.hpp24
-rw-r--r--test/algorithm/update_renderables.cpp1001
4 files changed, 879 insertions, 297 deletions
diff --git a/src/mbgl/algorithm/update_renderables.hpp b/src/mbgl/algorithm/update_renderables.hpp
index 8948b8eafe..22d4205d90 100644
--- a/src/mbgl/algorithm/update_renderables.hpp
+++ b/src/mbgl/algorithm/update_renderables.hpp
@@ -2,65 +2,69 @@
#include <mbgl/tile/tile_id.hpp>
-#include <map>
+#include <set>
namespace mbgl {
namespace algorithm {
-namespace {
-
-template <typename DataTiles, typename Renderables>
-bool tryTile(const UnwrappedTileID& renderTileID,
- const OverscaledTileID& dataTileID,
- const DataTiles& dataTiles,
- Renderables& renderables) {
- if (renderables.find(renderTileID) == renderables.end()) {
- const auto it = dataTiles.find(dataTileID);
- if (it == dataTiles.end() || !it->second->isRenderable()) {
- return false;
- }
-
- using Renderable = typename Renderables::mapped_type;
- renderables.emplace(renderTileID, Renderable{ renderTileID, *it->second });
- }
-
- return true;
-}
-
-} // namespace
-
-template <typename Renderable, typename DataTiles, typename IdealTileIDs, typename SourceInfo>
-std::map<UnwrappedTileID, Renderable> updateRenderables(const DataTiles& dataTiles,
- const IdealTileIDs& idealTileIDs,
- const SourceInfo& info,
- const uint8_t z) {
- std::map<UnwrappedTileID, Renderable> renderables;
+template <typename GetTileDataFn,
+ typename CreateTileDataFn,
+ typename RetainTileDataFn,
+ typename RenderTileFn,
+ typename IdealTileIDs,
+ typename SourceInfo>
+void updateRenderables(GetTileDataFn getTileData,
+ CreateTileDataFn createTileData,
+ RetainTileDataFn retainTileData,
+ RenderTileFn renderTile,
+ const IdealTileIDs& idealTileIDs,
+ const SourceInfo& info,
+ const uint8_t dataTileZoom) {
+ std::set<UnwrappedTileID> checked;
+ bool covered;
+ int32_t overscaledZ;
// for (all in the set of ideal tiles of the source) {
- for (const auto& renderTileID : idealTileIDs) {
- assert(renderTileID.canonical.z >= info.minZoom);
- assert(renderTileID.canonical.z <= info.maxZoom);
- assert(z >= renderTileID.canonical.z);
- const auto wrap = renderTileID.wrap;
- const OverscaledTileID dataTileID(z, renderTileID.canonical);
+ for (const auto& idealRenderTileID : idealTileIDs) {
+ assert(idealRenderTileID.canonical.z >= info.minZoom);
+ assert(idealRenderTileID.canonical.z <= info.maxZoom);
+ assert(dataTileZoom >= idealRenderTileID.canonical.z);
+
+ const OverscaledTileID idealDataTileID(dataTileZoom, idealRenderTileID.canonical);
+ auto data = getTileData(idealDataTileID);
+ if (!data) {
+ data = createTileData(idealDataTileID);
+ assert(data);
+ }
// if (source has the tile and bucket is loaded) {
- if (!tryTile(renderTileID, dataTileID, dataTiles, renderables)) {
- // The source doesn't have the tile, or the bucket isn't loaded.
- bool covered = true;
- int32_t overscaledZ = z + 1;
+ if (data->isRenderable()) {
+ retainTileData(*data);
+ renderTile(idealRenderTileID, *data);
+ } else {
+ // The tile isn't loaded yet, but retain it anyway because it's an ideal tile.
+ retainTileData(*data);
+ covered = true;
+ overscaledZ = dataTileZoom + 1;
if (overscaledZ > info.maxZoom) {
// We're looking for an overzoomed child tile.
- const auto childDataTileID = dataTileID.scaledTo(overscaledZ);
- if (!tryTile(renderTileID, childDataTileID, dataTiles, renderables)) {
+ const auto childDataTileID = idealDataTileID.scaledTo(overscaledZ);
+ data = getTileData(childDataTileID);
+ if (data && data->isRenderable()) {
+ retainTileData(*data);
+ renderTile(idealRenderTileID, *data);
+ } else {
covered = false;
}
} else {
// Check all four actual child tiles.
- for (const auto& childTileID : dataTileID.canonical.children()) {
+ for (const auto& childTileID : idealDataTileID.canonical.children()) {
const OverscaledTileID childDataTileID(overscaledZ, childTileID);
- const UnwrappedTileID childRenderTileID(wrap, childTileID);
- if (!tryTile(childRenderTileID, childDataTileID, dataTiles, renderables)) {
+ data = getTileData(childDataTileID);
+ if (data && data->isRenderable()) {
+ retainTileData(*data);
+ renderTile(childDataTileID.unwrapTo(idealRenderTileID.wrap), *data);
+ } else {
// At least one child tile doesn't exist, so we are going to look for
// parents as well.
covered = false;
@@ -70,10 +74,23 @@ std::map<UnwrappedTileID, Renderable> updateRenderables(const DataTiles& dataTil
if (!covered) {
// We couldn't find child tiles that entirely cover the ideal tile.
- for (overscaledZ = z - 1; overscaledZ >= info.minZoom; --overscaledZ) {
- const auto parentDataTileID = dataTileID.scaledTo(overscaledZ);
- const auto parentRenderTileID = parentDataTileID.unwrapTo(renderTileID.wrap);
- if (tryTile(parentRenderTileID, parentDataTileID, dataTiles, renderables)) {
+ for (overscaledZ = dataTileZoom - 1; overscaledZ >= info.minZoom; --overscaledZ) {
+ const auto parentDataTileID = idealDataTileID.scaledTo(overscaledZ);
+ const auto parentRenderTileID =
+ parentDataTileID.unwrapTo(idealRenderTileID.wrap);
+
+ if (checked.find(parentRenderTileID) != checked.end()) {
+ // Break parent tile ascent, this route has been checked by another child
+ // tile before.
+ break;
+ } else {
+ checked.emplace(parentRenderTileID);
+ }
+
+ data = getTileData(parentDataTileID);
+ if (data && data->isRenderable()) {
+ retainTileData(*data);
+ renderTile(parentRenderTileID, *data);
// Break parent tile ascent, since we found one.
break;
}
@@ -81,8 +98,6 @@ std::map<UnwrappedTileID, Renderable> updateRenderables(const DataTiles& dataTil
}
}
}
-
- return renderables;
}
} // namespace algorithm
diff --git a/src/mbgl/source/source.cpp b/src/mbgl/source/source.cpp
index 5f2b54485b..1c55b9c024 100644
--- a/src/mbgl/source/source.cpp
+++ b/src/mbgl/source/source.cpp
@@ -251,7 +251,7 @@ bool Source::update(const StyleUpdateParameters& parameters) {
}
idealTiles = util::tileCover(parameters.transformState, idealZoom);
- }
+ }
// Stores a list of all the data tiles that we're definitely going to retain. There are two
// kinds of tiles we need: the ideal tiles determined by the tile cover. They may not yet be in
@@ -259,24 +259,26 @@ bool Source::update(const StyleUpdateParameters& parameters) {
// we're actively using, e.g. as a replacement for tile that aren't loaded yet.
std::set<OverscaledTileID> retain;
- // Create all tiles that we definitely want to load
- for (const auto& unwrappedTileID : idealTiles) {
- const OverscaledTileID dataTileID(dataTileZoom, unwrappedTileID.canonical);
- retain.emplace(dataTileID);
-
- auto it = tileDataMap.find(dataTileID);
- if (it == tileDataMap.end()) {
- if (auto data = createTile(dataTileID, parameters)) {
- it = tileDataMap.emplace(dataTileID, std::move(data)).first;
- }
+ auto retainTileDataFn = [&retain](const TileData& tileData) -> void {
+ retain.emplace(tileData.id);
+ };
+ auto getTileDataFn = [this](const OverscaledTileID& dataTileID) -> TileData* {
+ return getTileData(dataTileID);
+ };
+ auto createTileDataFn = [this, &parameters](const OverscaledTileID& dataTileID) -> TileData* {
+ if (auto data = createTile(dataTileID, parameters)) {
+ return tileDataMap.emplace(dataTileID, std::move(data)).first->second.get();
+ } else {
+ return nullptr;
}
- }
-
- tiles = algorithm::updateRenderables<Tile>(tileDataMap, idealTiles, *info, overscaledZoom);
+ };
+ auto renderTileFn = [this](const UnwrappedTileID& renderTileID, TileData& tileData) {
+ tiles.emplace(renderTileID, Tile{ renderTileID, tileData });
+ };
- for (auto& pair : tiles) {
- retain.emplace(pair.second.data.id);
- }
+ tiles.clear();
+ algorithm::updateRenderables(getTileDataFn, createTileDataFn, retainTileDataFn, renderTileFn,
+ idealTiles, *info, dataTileZoom);
if (type != SourceType::Raster && type != SourceType::Annotations && cache.getSize() == 0) {
size_t conservativeCacheSize =
diff --git a/test/algorithm/mock.hpp b/test/algorithm/mock.hpp
index a1ee534f79..28c78854be 100644
--- a/test/algorithm/mock.hpp
+++ b/test/algorithm/mock.hpp
@@ -15,26 +15,10 @@ struct MockSourceInfo {
struct MockTileData;
-struct MockRenderable {
- MockRenderable(mbgl::UnwrappedTileID id_, MockTileData& data_) : id(id_), data(data_) {}
-
- const mbgl::UnwrappedTileID id;
- MockTileData& data;
-
- bool operator==(const MockRenderable& rhs) const {
- return &data == &rhs.data;
- }
-};
-
-::std::ostream& operator<<(::std::ostream& os, const MockRenderable&) {
- return os << "Renderable{}";
-}
-
struct MockSource {
MockSourceInfo info;
std::map<mbgl::OverscaledTileID, std::unique_ptr<MockTileData>> dataTiles;
std::set<mbgl::UnwrappedTileID> idealTiles;
- std::map<mbgl::UnwrappedTileID, MockRenderable> renderables;
// Test API
inline MockTileData* createTileData(const mbgl::OverscaledTileID& tileID);
@@ -44,14 +28,16 @@ struct MockBucket {};
struct MockTileData {
+ MockTileData(const mbgl::OverscaledTileID& tileID_) : tileID(tileID_) {}
bool isRenderable() {
- return ready;
+ return renderable;
}
- bool ready = false;
+ bool renderable = false;
+ const mbgl::OverscaledTileID tileID;
};
MockTileData* MockSource::createTileData(const mbgl::OverscaledTileID& tileID) {
// Replace the existing MockTileData object, if any.
- return (dataTiles[tileID] = std::make_unique<MockTileData>()).get();
+ return (dataTiles[tileID] = std::make_unique<MockTileData>(tileID)).get();
}
diff --git a/test/algorithm/update_renderables.cpp b/test/algorithm/update_renderables.cpp
index 704cd770db..67c7d79a0a 100644
--- a/test/algorithm/update_renderables.cpp
+++ b/test/algorithm/update_renderables.cpp
@@ -1,367 +1,946 @@
-#include <mbgl/test/util.hpp>
#include "mock.hpp"
+#include <mbgl/test/util.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <mapbox/variant_io.hpp>
#include <mbgl/algorithm/update_renderables.hpp>
using namespace mbgl;
+struct GetTileDataAction {
+ const OverscaledTileID tileID;
+ const bool found;
+
+ bool operator==(const GetTileDataAction& rhs) const {
+ return tileID == rhs.tileID && found == rhs.found;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const GetTileDataAction& action) {
+ return os << "GetTileDataAction{ { " << int(action.tileID.overscaledZ) << ", { "
+ << int(action.tileID.canonical.z) << ", " << action.tileID.canonical.x << ", "
+ << action.tileID.canonical.y << " } }, " << (action.found ? "true" : "false") << " }";
+}
+
+struct CreateTileDataAction {
+ const OverscaledTileID tileID;
+
+ bool operator==(const CreateTileDataAction& rhs) const {
+ return tileID == rhs.tileID;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const CreateTileDataAction& action) {
+ return os << "CreateTileDataAction{ { " << int(action.tileID.overscaledZ) << ", { "
+ << int(action.tileID.canonical.z) << ", " << action.tileID.canonical.x << ", "
+ << action.tileID.canonical.y << " } } }";
+}
+
+struct RetainTileDataAction {
+ const OverscaledTileID tileID;
+
+ bool operator==(const RetainTileDataAction& rhs) const {
+ return tileID == rhs.tileID;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const RetainTileDataAction& action) {
+ return os << "RetainTileDataAction{ { " << int(action.tileID.overscaledZ) << ", { "
+ << int(action.tileID.canonical.z) << ", " << action.tileID.canonical.x << ", "
+ << action.tileID.canonical.y << " } } }";
+}
+
+struct RenderTileAction {
+ const UnwrappedTileID tileID;
+ const MockTileData& tileData;
+
+ bool operator==(const RenderTileAction& rhs) const {
+ return tileID == rhs.tileID && &tileData == &rhs.tileData;
+ }
+};
+
+std::ostream& operator<<(std::ostream& os, const RenderTileAction& action) {
+ const int64_t x =
+ (1ul << action.tileID.canonical.z) * action.tileID.wrap + action.tileID.canonical.x;
+ return os << "RenderTileAction{ { " << int(action.tileID.canonical.z) << ", " << x << ", "
+ << action.tileID.canonical.y << " }, *tile_"
+ << int(action.tileData.tileID.overscaledZ) << "_"
+ << int(action.tileData.tileID.canonical.z) << "_"
+ << action.tileData.tileID.canonical.x << "_" << action.tileData.tileID.canonical.y
+ << " }";
+}
+
+using ActionLogEntry =
+ variant<GetTileDataAction, CreateTileDataAction, RetainTileDataAction, RenderTileAction>;
+using ActionLog = std::vector<ActionLogEntry>;
+
+template <typename T>
+auto getTileDataFn(ActionLog& log, const T& dataTiles) {
+ return [&](const auto& id) {
+ auto it = dataTiles.find(id);
+ log.emplace_back(GetTileDataAction{ id, it != dataTiles.end() });
+ return (it != dataTiles.end()) ? it->second.get() : nullptr;
+ };
+}
+
+template <typename T>
+auto createTileDataFn(ActionLog& log, T& dataTiles) {
+ return [&](const auto& id) {
+ log.emplace_back(CreateTileDataAction{ id });
+ return (dataTiles[id] = std::make_unique<MockTileData>(id)).get();
+ };
+}
+
+auto retainTileDataFn(ActionLog& log) {
+ return [&](auto& tileData) { log.emplace_back(RetainTileDataAction{ tileData.tileID }); };
+}
+
+auto renderTileFn(ActionLog& log) {
+ return [&](const auto& id, auto& tileData) {
+ log.emplace_back(RenderTileAction{ id, tileData });
+ };
+}
+
TEST(UpdateRenderables, SingleTile) {
+ ActionLog log;
MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
source.idealTiles.emplace(UnwrappedTileID{ 1, 1, 1 });
// Make sure that we're getting the tile back.
- auto tile_1_1_1 = source.createTileData(OverscaledTileID{ 1, 1, 1 });
- tile_1_1_1->ready = true;
-
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } },
+ auto tile_1_1_1_1 = source.createTileData(OverscaledTileID{ 1, 1, 1 });
+ tile_1_1_1_1->renderable = true;
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 1, 1 } }, true }, // found ideal tile
+ RetainTileDataAction{ { 1, { 1, 1, 1 } } }, //
+ RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render ideal tile
}),
- source.renderables);
+ log);
// Check a repeated render with the same data.
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } },
+ log.clear();
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 1, 1 } }, true }, // found ideal tile
+ RetainTileDataAction{ { 1, { 1, 1, 1 } } }, //
+ RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render ideal tile
}),
- source.renderables);
+ log);
// Insert a tile we don't have data for.
+ log.clear();
source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 1 });
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } },
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 1 } }, false }, // missing ideal tile
+ CreateTileDataAction{ { 1, { 1, 0, 1 } } }, // create ideal tile
+ RetainTileDataAction{ { 1, { 1, 0, 1 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 2 } }, false }, // four child tiles
+ GetTileDataAction{ { 2, { 2, 0, 3 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 2 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 3 } }, false }, // ...
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, false }, // parent tile
+
+ GetTileDataAction{ { 1, { 1, 1, 1 } }, true }, // found ideal tile
+ RetainTileDataAction{ { 1, { 1, 1, 1 } } }, //
+ RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render found tile
}),
- source.renderables);
+ log);
// Now insert the missing tile and check that we're rendering it.
- auto tile_1_0_1 = source.createTileData(OverscaledTileID{ 1, 0, 1 });
- tile_1_0_1->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } },
- { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } },
+ log.clear();
+ auto tile_1_1_0_1 = source.createTileData(OverscaledTileID{ 1, 0, 1 });
+ tile_1_1_0_1->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 1 } }, true }, // newly added tile
+ RetainTileDataAction{ { 1, { 1, 0, 1 } } }, //
+ RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, // render ideal tile
+
+ GetTileDataAction{ { 1, { 1, 1, 1 } }, true }, // ideal tile
+ RetainTileDataAction{ { 1, { 1, 1, 1 } } }, //
+ RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render found tile
}),
- source.renderables);
+ log);
// Insert another tile, and another bucket that has a different name and check that we're not
// using it.
+ log.clear();
source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 });
- auto tile_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, 0 });
-
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } },
- { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } },
+ auto tile_1_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, 0 });
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, // found tile, not ready
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, // four child tiles
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, false }, // ...
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, false }, // parent tile
+
+ GetTileDataAction{ { 1, { 1, 0, 1 } }, true }, // ideal tile
+ RetainTileDataAction{ { 1, { 1, 0, 1 } } }, //
+ RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, // render ideal tile
+
+ GetTileDataAction{ { 1, { 1, 1, 1 } }, true }, // ideal tile
+ RetainTileDataAction{ { 1, { 1, 1, 1 } } }, //
+ RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, // render ideal tile
}),
- source.renderables);
+ log);
// Then, add the bucket and check that it's getting used.
- tile_1_0_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 0, 0 }, MockRenderable{ { 1, 0, 0 }, *tile_1_0_0 } },
- { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } },
- { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } },
- }),
- source.renderables);
+ log.clear();
+ tile_1_1_0_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, // found tile, now ready
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ RenderTileAction{ { 1, 0, 0 }, *tile_1_1_0_0 }, //
+
+ GetTileDataAction{ { 1, { 1, 0, 1 } }, true }, // ideal tile
+ RetainTileDataAction{ { 1, { 1, 0, 1 } } }, //
+ RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, //
+
+ GetTileDataAction{ { 1, { 1, 1, 1 } }, true }, // ideal tile
+ RetainTileDataAction{ { 1, { 1, 1, 1 } } }, //
+ RenderTileAction{ { 1, 1, 1 }, *tile_1_1_1_1 }, //
+ }),
+ log);
}
TEST(UpdateRenderables, UseParentTile) {
+ ActionLog log;
MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 1 });
source.idealTiles.emplace(UnwrappedTileID{ 1, 1, 0 });
source.idealTiles.emplace(UnwrappedTileID{ 1, 1, 1 });
// Make sure that we're getting the tile back.
- auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
- tile_0_0_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } },
- }),
- source.renderables);
+ auto tile_0_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
+ tile_0_0_0_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 1 } }, false }, // missing ideal tile
+ CreateTileDataAction{ { 1, { 1, 0, 1 } } }, //
+ RetainTileDataAction{ { 1, { 1, 0, 1 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 2 } }, false }, // child tile
+ GetTileDataAction{ { 2, { 2, 0, 3 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 2 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 3 } }, false }, // ...
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, // parent found!
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, // render parent
+ GetTileDataAction{ { 1, { 1, 1, 0 } }, false }, // missing ideal tile
+ CreateTileDataAction{ { 1, { 1, 1, 0 } } }, //
+ RetainTileDataAction{ { 1, { 1, 1, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 2, 0 } }, false }, // child tile
+ GetTileDataAction{ { 2, { 2, 2, 1 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 3, 0 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 3, 1 } }, false }, // ...
+ GetTileDataAction{ { 1, { 1, 1, 1 } }, false }, // missing tile
+ CreateTileDataAction{ { 1, { 1, 1, 1 } } }, //
+ RetainTileDataAction{ { 1, { 1, 1, 1 } } }, //
+ GetTileDataAction{ { 2, { 2, 2, 2 } }, false }, // child tile
+ GetTileDataAction{ { 2, { 2, 2, 3 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 3, 2 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 3, 3 } }, false }, // ...
+ }),
+ log);
}
TEST(UpdateRenderables, DontUseWrongParentTile) {
+ ActionLog log;
MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 });
- auto tile_1_1_0 = source.createTileData(OverscaledTileID{ 1, 1, 0 });
- tile_1_1_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 2);
- EXPECT_EQ(decltype(source.renderables)({}), source.renderables);
+ auto tile_1_1_1_0 = source.createTileData(OverscaledTileID{ 1, 1, 0 });
+ tile_1_1_1_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 2);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, // missing ideal tile
+ CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ GetTileDataAction{ { 3, { 3, 0, 0 } }, false }, // child tile
+ GetTileDataAction{ { 3, { 3, 0, 1 } }, false }, // ...
+ GetTileDataAction{ { 3, { 3, 1, 0 } }, false }, // ...
+ GetTileDataAction{ { 3, { 3, 1, 1 } }, false }, // ...
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, false }, // parent tile, missing
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, false }, // parent tile, missing
+ }),
+ log);
// Add a new child tile and check that it is now used.
+ log.clear();
source.idealTiles.emplace(UnwrappedTileID{ 2, 2, 0 });
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 2);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 1, 0 }, MockRenderable{ { 1, 1, 0 }, *tile_1_1_0 } },
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 2);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, // non-ready ideal tile
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ // this tile was added by the previous invocation of updateRenderables
+ GetTileDataAction{ { 3, { 3, 0, 0 } }, false }, // child tile
+ GetTileDataAction{ { 3, { 3, 0, 1 } }, false }, // ...
+ GetTileDataAction{ { 3, { 3, 1, 0 } }, false }, // ...
+ GetTileDataAction{ { 3, { 3, 1, 1 } }, false }, // ...
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, false }, // missing parent tile
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, false }, // missing parent tile
+
+ GetTileDataAction{ { 2, { 2, 2, 0 } }, false }, // missing ideal tile
+ CreateTileDataAction{ { 2, { 2, 2, 0 } } }, //
+ RetainTileDataAction{ { 2, { 2, 2, 0 } } }, //
+ GetTileDataAction{ { 3, { 3, 4, 0 } }, false }, // child tile
+ GetTileDataAction{ { 3, { 3, 4, 1 } }, false }, // ...
+ GetTileDataAction{ { 3, { 3, 5, 0 } }, false }, // ...
+ GetTileDataAction{ { 3, { 3, 5, 1 } }, false }, // ...
+ GetTileDataAction{ { 1, { 1, 1, 0 } }, true }, // found parent tile
+ RetainTileDataAction{ { 1, { 1, 1, 0 } } }, //
+ RenderTileAction{ { 1, 1, 0 }, *tile_1_1_1_0 }, // render parent tile
}),
- source.renderables);
+ log);
}
TEST(UpdateRenderables, UseParentTileWhenChildNotReady) {
+ ActionLog log;
MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 1 });
- auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
- tile_0_0_0->ready = true;
+ auto tile_0_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
+ tile_0_0_0_0->renderable = true;
- auto tile_1_0_1 = source.createTileData(OverscaledTileID{ 1, 0, 1 });
+ auto tile_1_1_0_1 = source.createTileData(OverscaledTileID{ 1, 0, 1 });
// Don't create bucket.
// Make sure that it renders the parent tile.
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } },
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 1 } }, true }, // found, but not ready
+ RetainTileDataAction{ { 1, { 1, 0, 1 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 2 } }, false }, // child tile
+ GetTileDataAction{ { 2, { 2, 0, 3 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 2 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 3 } }, false }, // ...
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, // parent tile, ready
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, // render parent tile
}),
- source.renderables);
+ log);
// Now insert the bucket and make sure we're now using the matching tile
- tile_1_0_1->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } },
+ log.clear();
+ tile_1_1_0_1->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 1 } }, true }, // found and ready
+ RetainTileDataAction{ { 1, { 1, 0, 1 } } }, //
+ RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, // render ideal tile
}),
- source.renderables);
+ log);
}
TEST(UpdateRenderables, UseOverlappingParentTile) {
+ ActionLog log;
MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 });
source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 1 });
- auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
- tile_0_0_0->ready = true;
-
- auto tile_1_0_1 = source.createTileData(OverscaledTileID{ 1, 0, 1 });
- tile_1_0_1->ready = true;
-
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } },
- { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } },
+ auto tile_0_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
+ tile_0_0_0_0->renderable = true;
+
+ auto tile_1_1_0_1 = source.createTileData(OverscaledTileID{ 1, 0, 1 });
+ tile_1_1_0_1->renderable = true;
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, false }, // ideal tile not found
+ CreateTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, // child tile
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, false }, // ...
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, // parent tile found
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
+
+ GetTileDataAction{ { 1, { 1, 0, 1 } }, true }, // ideal tile found
+ RetainTileDataAction{ { 1, { 1, 0, 1 } } }, //
+ RenderTileAction{ { 1, 0, 1 }, *tile_1_1_0_1 }, //
}),
- source.renderables);
+ log);
}
TEST(UpdateRenderables, UseChildTiles) {
+ ActionLog log;
MockSource source;
- source.idealTiles.emplace(UnwrappedTileID{ 0, 0, 0 });
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
- auto tile_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, 0 });
- tile_1_0_0->ready = true;
- auto tile_1_1_0 = source.createTileData(OverscaledTileID{ 1, 1, 0 });
- tile_1_1_0->ready = true;
+ source.idealTiles.emplace(UnwrappedTileID{ 0, 0, 0 });
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 0);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 0, 0 }, MockRenderable{ { 1, 0, 0 }, *tile_1_0_0 } },
- { { 1, 1, 0 }, MockRenderable{ { 1, 1, 0 }, *tile_1_1_0 } },
+ auto tile_1_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, 0 });
+ tile_1_1_0_0->renderable = true;
+ auto tile_1_1_1_0 = source.createTileData(OverscaledTileID{ 1, 1, 0 });
+ tile_1_1_1_0->renderable = true;
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 0);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, false }, // ideal tile, missing
+ CreateTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, // child tile found
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ RenderTileAction{ { 1, 0, 0 }, *tile_1_1_0_0 }, // render child tile
+ GetTileDataAction{ { 1, { 1, 0, 1 } }, false }, // child tile not found
+ GetTileDataAction{ { 1, { 1, 1, 0 } }, true }, // child tile found
+ RetainTileDataAction{ { 1, { 1, 1, 0 } } }, //
+ RenderTileAction{ { 1, 1, 0 }, *tile_1_1_1_0 }, // render child tile
+ GetTileDataAction{ { 1, { 1, 1, 1 } }, false }, // child tile not found
+ // no parent tile of 0 to consider
}),
- source.renderables);
+ log);
}
TEST(UpdateRenderables, PreferChildTiles) {
+ ActionLog log;
MockSource source;
- source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 });
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
- auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
- tile_0_0_0->ready = true;
- auto tile_2_0_0 = source.createTileData(OverscaledTileID{ 2, 0, 0 });
- tile_2_0_0->ready = true;
+ source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 });
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } },
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } },
+ auto tile_0_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
+ tile_0_0_0_0->renderable = true;
+ auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, 0, 0 });
+ tile_2_2_0_0->renderable = true;
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, false }, // ideal tile, not found
+ CreateTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, // child tile, found
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, false }, // child tile, not found
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, false }, // ...
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, // parent tile, found
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
}),
- source.renderables);
+ log);
// Now add more children to cover the ideal tile fully, until it is covered fully, and verify
// that the parent doesn't get rendered.
- auto tile_2_0_1 = source.createTileData(OverscaledTileID{ 2, 0, 1 });
- tile_2_0_1->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } },
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } },
- { { 2, 0, 1 }, MockRenderable{ { 2, 0, 1 }, *tile_2_0_1 } },
- }),
- source.renderables);
-
- auto tile_2_1_0 = source.createTileData(OverscaledTileID{ 2, 1, 0 });
- tile_2_1_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } },
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } },
- { { 2, 0, 1 }, MockRenderable{ { 2, 0, 1 }, *tile_2_0_1 } },
- { { 2, 1, 0 }, MockRenderable{ { 2, 1, 0 }, *tile_2_1_0 } },
- }),
- source.renderables);
+ log.clear();
+ auto tile_2_2_0_1 = source.createTileData(OverscaledTileID{ 2, 0, 1 });
+ tile_2_2_0_1->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, // ideal tile, not ready
+ // ideal tile was added in previous invocation, but is not yet ready
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, // child tile, found
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, true }, // ...
+ RetainTileDataAction{ { 2, { 2, 0, 1 } } }, // ...
+ RenderTileAction{ { 2, 0, 1 }, *tile_2_2_0_1 }, //
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, false }, // child tile, not found
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, false }, // ...
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, // parent tile, found
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
+ }),
+ log);
+
+ log.clear();
+ auto tile_2_2_1_0 = source.createTileData(OverscaledTileID{ 2, 1, 0 });
+ tile_2_2_1_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, // ideal tile, not ready
+ // ideal tile was added in first invocation, but is not yet ready
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, // child tile, found
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, true }, // ...
+ RetainTileDataAction{ { 2, { 2, 0, 1 } } }, //
+ RenderTileAction{ { 2, 0, 1 }, *tile_2_2_0_1 }, //
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, true }, // ...
+ RetainTileDataAction{ { 2, { 2, 1, 0 } } }, //
+ RenderTileAction{ { 2, 1, 0 }, *tile_2_2_1_0 }, //
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, false }, // child tile, not found
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, // parent tile, found
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
+ }),
+ log);
// Adding the last child tile covers 1/0/0 fully, so we don't need 0/0/0 anymore.
- auto tile_2_1_1 = source.createTileData(OverscaledTileID{ 2, 1, 1 });
- tile_2_1_1->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } },
- { { 2, 0, 1 }, MockRenderable{ { 2, 0, 1 }, *tile_2_0_1 } },
- { { 2, 1, 0 }, MockRenderable{ { 2, 1, 0 }, *tile_2_1_0 } },
- { { 2, 1, 1 }, MockRenderable{ { 2, 1, 1 }, *tile_2_1_1 } },
- }),
- source.renderables);
+ log.clear();
+ auto tile_2_2_1_1 = source.createTileData(OverscaledTileID{ 2, 1, 1 });
+ tile_2_2_1_1->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, // ideal tile, not ready
+ // ideal tile was added in first invocation, but is not yet ready
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, // child tile, found
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, true }, // ...
+ RetainTileDataAction{ { 2, { 2, 0, 1 } } }, //
+ RenderTileAction{ { 2, 0, 1 }, *tile_2_2_0_1 }, //
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, true }, // ...
+ RetainTileDataAction{ { 2, { 2, 1, 0 } } }, //
+ RenderTileAction{ { 2, 1, 0 }, *tile_2_2_1_0 }, //
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, true }, // ...
+ RetainTileDataAction{ { 2, { 2, 1, 1 } } }, //
+ RenderTileAction{ { 2, 1, 1 }, *tile_2_2_1_1 }, //
+ }),
+ log);
}
TEST(UpdateRenderables, UseParentAndChildTiles) {
+ ActionLog log;
MockSource source;
- source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 });
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
- auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
- tile_0_0_0->ready = true;
- auto tile_2_0_0 = source.createTileData(OverscaledTileID{ 2, 0, 0 });
- tile_2_0_0->ready = true;
+ source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 });
- // Check that it uses the child tile, but not the parent tile.
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } },
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } },
+ auto tile_0_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 });
+ tile_0_0_0_0->renderable = true;
+ auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, 0, 0 });
+ tile_2_2_0_0->renderable = true;
+
+ // Check that it uses the child tile and the parent tile to cover the rest.
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, false }, // ideal tile, missing
+ CreateTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, false }, //
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
}),
- source.renderables);
+ log);
- // Then, remove the child tile and check that it now uses the parent tile.
+ // Then, remove the child tile and check that it now only the parent tile.
+ log.clear();
source.dataTiles.erase(OverscaledTileID{ 2, 0, 0 });
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 1);
- EXPECT_EQ(decltype(source.renderables)({
- { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } },
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, // ideal tile, not ready
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, false }, //
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
}),
- source.renderables);
+ log);
}
TEST(UpdateRenderables, DontUseTilesLowerThanMinzoom) {
+ ActionLog log;
MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
source.info.minZoom = 2;
source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 });
- auto tile_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, 0 });
- tile_1_0_0->ready = true;
-
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 2);
- EXPECT_EQ(decltype(source.renderables)({}), source.renderables);
+ auto tile_1_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, 0 });
+ tile_1_1_0_0->renderable = true;
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 2);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, // ideal tile, missing
+ CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ GetTileDataAction{ { 3, { 3, 0, 0 } }, false }, //
+ GetTileDataAction{ { 3, { 3, 0, 1 } }, false }, //
+ GetTileDataAction{ { 3, { 3, 1, 0 } }, false }, //
+ GetTileDataAction{ { 3, { 3, 1, 1 } }, false }, //
+ // no requests for zoom 1 tiles
+ }),
+ log);
}
TEST(UpdateRenderables, UseOverzoomedTileAfterMaxzoom) {
+ ActionLog log;
MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
source.info.maxZoom = 2;
source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 });
// Add a child tile (that should never occur in practice) and make sure it's not selected.
auto tile_3_3_0_0 = source.createTileData(OverscaledTileID{ 3, 0, 0 });
- tile_3_3_0_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 2);
- EXPECT_EQ(decltype(source.renderables)({}), source.renderables);
+ tile_3_3_0_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 2);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, // ideal tile, missing
+ CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ GetTileDataAction{ { 3, { 2, 0, 0 } }, false }, // overzoomed tile, not children!
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, false }, //
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, false }, //
+ }),
+ log);
// Only add a non-overzoomed ("parent") tile at first.
+ log.clear();
auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, { 2, 0, 0 } });
- tile_2_2_0_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 3);
- EXPECT_EQ(decltype(source.renderables)({
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_2_0_0 } },
+ tile_2_2_0_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 3);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 3, { 2, 0, 0 } }, false }, // ideal tile, missing
+ CreateTileDataAction{ { 3, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 3, { 2, 0, 0 } } }, //
+ GetTileDataAction{ { 4, { 2, 0, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
}),
- source.renderables);
+ log);
// Then add the overzoomed tile matching the zoom level we're rendering.
+ log.clear();
auto tile_3_2_0_0 = source.createTileData(OverscaledTileID{ 3, { 2, 0, 0 } });
- tile_3_2_0_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 3);
- EXPECT_EQ(decltype(source.renderables)({
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_3_2_0_0 } },
+ tile_3_2_0_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 3);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 3, { 2, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 3, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_3_2_0_0 }, //
}),
- source.renderables);
+ log);
// Check that it's switching back to the tile that has the matching overzoom value.
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 2);
- EXPECT_EQ(decltype(source.renderables)({
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_2_0_0 } },
+ log.clear();
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 2);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
}),
- source.renderables);
+ log);
// Now remove the best match.
+ log.clear();
source.dataTiles.erase(OverscaledTileID{ 2, { 2, 0, 0 } });
tile_2_2_0_0 = nullptr;
// Use the overzoomed tile even though it doesn't match the zoom level.
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 2);
- EXPECT_EQ(decltype(source.renderables)({
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_3_2_0_0 } },
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 2);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, //
+ CreateTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ GetTileDataAction{ { 3, { 2, 0, 0 } }, true }, // use overzoomed tile!
+ RetainTileDataAction{ { 3, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_3_2_0_0 }, //
}),
- source.renderables);
+ log);
}
TEST(UpdateRenderables, AscendToNonOverzoomedTiles) {
+ ActionLog log;
MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
source.info.maxZoom = 2;
source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 });
// Add a matching overzoomed tile and make sure it gets selected.
auto tile_3_2_0_0 = source.createTileData(OverscaledTileID{ 3, { 2, 0, 0 } });
- tile_3_2_0_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 3);
- EXPECT_EQ(decltype(source.renderables)({
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_3_2_0_0 } },
+ tile_3_2_0_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 3);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 3, { 2, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 3, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_3_2_0_0 }, //
}),
- source.renderables);
+ log);
// Then, swap it with a non-overzoomed tile.
+ log.clear();
source.dataTiles.erase(OverscaledTileID{ 3, { 2, 0, 0 } });
tile_3_2_0_0 = nullptr;
auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, { 2, 0, 0 } });
- tile_2_2_0_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 3);
- EXPECT_EQ(decltype(source.renderables)({
- { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_2_0_0 } },
+ tile_2_2_0_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 3);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 3, { 2, 0, 0 } }, false }, //
+ CreateTileDataAction{ { 3, { 2, 0, 0 } } }, //
+ RetainTileDataAction{ { 3, { 2, 0, 0 } } }, //
+ GetTileDataAction{ { 4, { 2, 0, 0 } }, false }, // prefer using a child first
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ RenderTileAction{ { 2, 0, 0 }, *tile_2_2_0_0 }, //
}),
- source.renderables);
+ log);
// Then, swap it with a parent tile.
+ log.clear();
source.dataTiles.erase(OverscaledTileID{ 2, { 2, 0, 0 } });
tile_2_2_0_0 = nullptr;
auto tile_1_1_0_0 = source.createTileData(OverscaledTileID{ 1, { 1, 0, 0 } });
- tile_1_1_0_0->ready = true;
- source.renderables = algorithm::updateRenderables<MockRenderable>(
- source.dataTiles, source.idealTiles, source.info, 3);
- EXPECT_EQ(decltype(source.renderables)({
- { { 1, 0, 0 }, MockRenderable{ { 1, 0, 0 }, *tile_1_1_0_0 } },
+ tile_1_1_0_0->renderable = true;
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 3);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 3, { 2, 0, 0 } }, true }, // ideal tile found, but not ready
+ RetainTileDataAction{ { 3, { 2, 0, 0 } } }, //
+ GetTileDataAction{ { 4, { 2, 0, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, //
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ RenderTileAction{ { 1, 0, 0 }, *tile_1_1_0_0 }, //
+ }),
+ log);
+}
+
+TEST(UpdateRenderables, DoNotAscendMultipleTimesIfNotFound) {
+ ActionLog log;
+ MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
+ source.idealTiles.emplace(UnwrappedTileID{ 8, 0, 0 });
+ source.idealTiles.emplace(UnwrappedTileID{ 8, 1, 0 });
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 8);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 8, { 8, 0, 0 } }, false }, // ideal tile
+ CreateTileDataAction{ { 8, { 8, 0, 0 } } }, //
+ RetainTileDataAction{ { 8, { 8, 0, 0 } } }, //
+ GetTileDataAction{ { 9, { 9, 0, 0 } }, false }, // child tile
+ GetTileDataAction{ { 9, { 9, 0, 1 } }, false }, // ...
+ GetTileDataAction{ { 9, { 9, 1, 0 } }, false }, // ...
+ GetTileDataAction{ { 9, { 9, 1, 1 } }, false }, // ...
+ GetTileDataAction{ { 7, { 7, 0, 0 } }, false }, // ascent
+ GetTileDataAction{ { 6, { 6, 0, 0 } }, false }, // ...
+ GetTileDataAction{ { 5, { 5, 0, 0 } }, false }, // ...
+ GetTileDataAction{ { 4, { 4, 0, 0 } }, false }, // ...
+ GetTileDataAction{ { 3, { 3, 0, 0 } }, false }, // ...
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, // ...
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, false }, // ...
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, false }, // ...
+
+ GetTileDataAction{ { 8, { 8, 1, 0 } }, false }, // ideal tile
+ CreateTileDataAction{ { 8, { 8, 1, 0 } } }, //
+ RetainTileDataAction{ { 8, { 8, 1, 0 } } }, //
+ GetTileDataAction{ { 9, { 9, 2, 0 } }, false }, // child tile
+ GetTileDataAction{ { 9, { 9, 2, 1 } }, false }, // ...
+ GetTileDataAction{ { 9, { 9, 3, 0 } }, false }, // ...
+ GetTileDataAction{ { 9, { 9, 3, 1 } }, false }, // ...
+ // no second ascent to 0
+ }),
+ log);
+
+ // Now add a mid-level tile that stops the ascent
+ log.clear();
+ auto tile_4_0_0_0 = source.createTileData(OverscaledTileID{ 4, { 4, 0, 0 } });
+ tile_4_0_0_0->renderable = true;
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 8);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 8, { 8, 0, 0 } }, true }, // ideal tile found, but not ready
+ RetainTileDataAction{ { 8, { 8, 0, 0 } } }, //
+ GetTileDataAction{ { 9, { 9, 0, 0 } }, false }, // child tile
+ GetTileDataAction{ { 9, { 9, 0, 1 } }, false }, // ...
+ GetTileDataAction{ { 9, { 9, 1, 0 } }, false }, // ...
+ GetTileDataAction{ { 9, { 9, 1, 1 } }, false }, // ...
+ GetTileDataAction{ { 7, { 7, 0, 0 } }, false }, // ascent
+ GetTileDataAction{ { 6, { 6, 0, 0 } }, false }, // ...
+ GetTileDataAction{ { 5, { 5, 0, 0 } }, false }, // ...
+ GetTileDataAction{ { 4, { 4, 0, 0 } }, true }, // stops ascent
+ RetainTileDataAction{ { 4, { 4, 0, 0 } } }, //
+ RenderTileAction{ { 4, 0, 0 }, *tile_4_0_0_0 },
+
+ GetTileDataAction{ { 8, { 8, 1, 0 } }, true }, // ideal tile found, but not ready
+ RetainTileDataAction{ { 8, { 8, 1, 0 } } }, //
+ GetTileDataAction{ { 9, { 9, 2, 0 } }, false }, // child tile
+ GetTileDataAction{ { 9, { 9, 2, 1 } }, false }, // ...
+ GetTileDataAction{ { 9, { 9, 3, 0 } }, false }, // ...
+ GetTileDataAction{ { 9, { 9, 3, 1 } }, false }, // ...
+ // no second ascent to 0
+ }),
+ log);
+}
+
+TEST(UpdateRenderables, DontRetainUnusedNonIdealTiles) {
+ ActionLog log;
+ MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
+ source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 });
+
+ source.createTileData(OverscaledTileID{ 1, 0, 0 });
+ source.createTileData(OverscaledTileID{ 2, 0, 0 });
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 2);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, true }, // ideal tile, not ready
+ RetainTileDataAction{ { 2, { 2, 0, 0 } } }, //
+ GetTileDataAction{ { 3, { 3, 0, 0 } }, false }, //
+ GetTileDataAction{ { 3, { 3, 0, 1 } }, false }, //
+ GetTileDataAction{ { 3, { 3, 1, 0 } }, false }, //
+ GetTileDataAction{ { 3, { 3, 1, 1 } }, false }, //
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, // parent tile, not ready
+ // don't retain the parent tile
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, false }, //
+ }),
+ log);
+}
+
+TEST(UpdateRenderables, WrappedTiles) {
+ ActionLog log;
+ MockSource source;
+ auto getTileData = getTileDataFn(log, source.dataTiles);
+ auto createTileData = createTileDataFn(log, source.dataTiles);
+ auto retainTileData = retainTileDataFn(log);
+ auto renderTile = renderTileFn(log);
+
+ source.idealTiles.emplace(UnwrappedTileID{ 1, -1, 0 });
+ source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 });
+ source.idealTiles.emplace(UnwrappedTileID{ 1, 1, 0 });
+ source.idealTiles.emplace(UnwrappedTileID{ 1, 2, 0 });
+
+ auto tile_0_0_0_0 = source.createTileData(OverscaledTileID{ 0, { 0, 0, 0 } });
+ tile_0_0_0_0->renderable = true;
+
+ algorithm::updateRenderables(getTileData, createTileData, retainTileData, renderTile,
+ source.idealTiles, source.info, 1);
+ EXPECT_EQ(ActionLog({
+ GetTileDataAction{ { 1, { 1, 1, 0 } }, false }, // ideal tile 1/-1/0
+ CreateTileDataAction{ { 1, { 1, 1, 0 } } }, //
+ RetainTileDataAction{ { 1, { 1, 1, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 2, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 2, 1 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 3, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 3, 1 } }, false }, //
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, -1, 0 }, *tile_0_0_0_0 }, //
+
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, false }, // ideal tile 1/0/0
+ CreateTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, false }, //
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 0, 0 }, *tile_0_0_0_0 }, //
+
+ GetTileDataAction{ { 1, { 1, 1, 0 } }, true }, // ideal tile 1/1/0
+ RetainTileDataAction{ { 1, { 1, 1, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 2, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 2, 1 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 3, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 3, 1 } }, false }, //
+ // do not ascent; 0/0/0 has been rendered already for 1/0/0
+
+ GetTileDataAction{ { 1, { 1, 0, 0 } }, true }, // ideal tile 1/2/0
+ RetainTileDataAction{ { 1, { 1, 0, 0 } } }, //
+ GetTileDataAction{ { 2, { 2, 0, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 0, 1 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 1, 0 } }, false }, //
+ GetTileDataAction{ { 2, { 2, 1, 1 } }, false }, //
+ GetTileDataAction{ { 0, { 0, 0, 0 } }, true }, //
+ RetainTileDataAction{ { 0, { 0, 0, 0 } } }, //
+ RenderTileAction{ { 0, 1, 0 }, *tile_0_0_0_0 }, //
}),
- source.renderables);
+ log);
}