Asynchronous GeometryTile deletion (#2051)
Co-authored-by: Tim Sylvester <tim@wetdogweather.com>
This commit is contained in:
@@ -2,9 +2,7 @@ load("//bazel:flags.bzl", "CPP_FLAGS", "MAPLIBRE_FLAGS")
|
||||
|
||||
cc_library(
|
||||
name = "testutils",
|
||||
hdrs = [
|
||||
"include/mbgl/test/util.hpp",
|
||||
],
|
||||
hdrs = glob(["include/mbgl/test/*.hpp"]),
|
||||
strip_include_prefix = "include",
|
||||
deps = [
|
||||
"//vendor/googletest:gtest",
|
||||
|
||||
@@ -91,7 +91,12 @@ TEST(Actor, DestructionBlocksOnSend) {
|
||||
|
||||
~TestScheduler() override { EXPECT_TRUE(waited.load()); }
|
||||
|
||||
void schedule(std::function<void()>) final {
|
||||
std::size_t waitForEmpty(Milliseconds) override {
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void schedule(std::function<void()>&&) final {
|
||||
promise.set_value();
|
||||
future.wait();
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
49
test/include/mbgl/test/vector_tile_test.hpp
Normal file
49
test/include/mbgl/test/vector_tile_test.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <mbgl/map/transform.hpp>
|
||||
#include <mbgl/renderer/tile_parameters.hpp>
|
||||
#include <mbgl/renderer/image_manager.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/test/fake_file_source.hpp>
|
||||
#include <mbgl/text/glyph_manager.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <mbgl/test/util.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class VectorTileTest {
|
||||
public:
|
||||
std::shared_ptr<FileSource> fileSource = std::make_shared<FakeFileSource>();
|
||||
TransformState transformState;
|
||||
util::RunLoop loop;
|
||||
style::Style style{fileSource, 1};
|
||||
AnnotationManager annotationManager{style};
|
||||
|
||||
const std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
|
||||
const std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
|
||||
|
||||
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
|
||||
|
||||
const std::shared_ptr<Scheduler> threadPool = Scheduler::GetBackground();
|
||||
|
||||
TileParameters tileParameters{1.0,
|
||||
MapDebugOptions(),
|
||||
transformState,
|
||||
fileSource,
|
||||
MapMode::Continuous,
|
||||
annotationManager.makeWeakPtr(),
|
||||
imageManager,
|
||||
glyphManager,
|
||||
0};
|
||||
|
||||
~VectorTileTest() {
|
||||
// Ensure that deferred releases are complete before cleaning up
|
||||
EXPECT_EQ(0, loop.waitForEmpty(Milliseconds::zero()));
|
||||
EXPECT_EQ(0, threadPool->waitForEmpty());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -1451,11 +1451,14 @@ TEST(Map, KeepRenderData) {
|
||||
test.map.getStyle().loadURL("maptiler://maps/streets");
|
||||
const int iterations = 3;
|
||||
const int resourcesCount = 4 /*tiles*/;
|
||||
|
||||
requestsCount = 0;
|
||||
// Keep render data.
|
||||
for (int i = 1; i <= iterations; ++i) {
|
||||
test.frontend.render(test.map);
|
||||
EXPECT_EQ(resourcesCount, requestsCount);
|
||||
}
|
||||
|
||||
requestsCount = 0;
|
||||
// Clear render data.
|
||||
for (int i = 1; i <= iterations; ++i) {
|
||||
|
||||
@@ -33,6 +33,8 @@ TEST(ImageManager, Basic) {
|
||||
ASSERT_TRUE(stored);
|
||||
EXPECT_EQ(image->image.size, stored->image.size);
|
||||
}
|
||||
|
||||
imageManager.dumpDebugLogs();
|
||||
}
|
||||
|
||||
TEST(ImageManager, AddRemove) {
|
||||
@@ -79,7 +81,7 @@ TEST(ImageManager, RemoveReleasesBinPackRect) {
|
||||
|
||||
class StubImageRequestor : public ImageRequestor {
|
||||
public:
|
||||
StubImageRequestor(ImageManager& imageManager_)
|
||||
StubImageRequestor(std::shared_ptr<ImageManager> imageManager_)
|
||||
: ImageRequestor(imageManager_) {}
|
||||
|
||||
void onImagesAvailable(ImageMap icons,
|
||||
@@ -95,8 +97,9 @@ public:
|
||||
|
||||
TEST(ImageManager, NotifiesRequestorWhenSpriteIsLoaded) {
|
||||
util::RunLoop runLoop;
|
||||
ImageManager imageManager;
|
||||
StubImageRequestor requestor(imageManager);
|
||||
auto imageManagerPtr = std::make_shared<ImageManager>();
|
||||
auto& imageManager = *imageManagerPtr;
|
||||
StubImageRequestor requestor(imageManagerPtr);
|
||||
bool notified = false;
|
||||
|
||||
ImageManagerObserver observer;
|
||||
@@ -123,8 +126,9 @@ TEST(ImageManager, NotifiesRequestorWhenSpriteIsLoaded) {
|
||||
}
|
||||
|
||||
TEST(ImageManager, NotifiesRequestorImmediatelyIfDependenciesAreSatisfied) {
|
||||
ImageManager imageManager;
|
||||
StubImageRequestor requestor(imageManager);
|
||||
auto imageManagerPtr = std::make_shared<ImageManager>();
|
||||
auto& imageManager = *imageManagerPtr;
|
||||
StubImageRequestor requestor(imageManagerPtr);
|
||||
bool notified = false;
|
||||
|
||||
requestor.imagesAvailable = [&](ImageMap, ImageMap, std::unordered_map<std::string, uint32_t>) {
|
||||
@@ -160,8 +164,9 @@ public:
|
||||
|
||||
TEST(ImageManager, OnStyleImageMissingBeforeSpriteLoaded) {
|
||||
util::RunLoop runLoop;
|
||||
ImageManager imageManager;
|
||||
StubImageRequestor requestor(imageManager);
|
||||
auto imageManagerPtr = std::make_shared<ImageManager>();
|
||||
auto& imageManager = *imageManagerPtr;
|
||||
StubImageRequestor requestor(imageManagerPtr);
|
||||
StubImageManagerObserver observer;
|
||||
|
||||
imageManager.setObserver(&observer);
|
||||
@@ -203,7 +208,7 @@ TEST(ImageManager, OnStyleImageMissingBeforeSpriteLoaded) {
|
||||
ASSERT_FALSE(requestor.hasPendingRequests());
|
||||
|
||||
// Another requestor shall not have pending requests for already obtained images.
|
||||
StubImageRequestor anotherRequestor(imageManager);
|
||||
StubImageRequestor anotherRequestor(imageManagerPtr);
|
||||
imageManager.getImages(anotherRequestor, std::make_pair(dependencies, ++imageCorrelationID));
|
||||
ASSERT_FALSE(anotherRequestor.hasPendingRequests());
|
||||
|
||||
@@ -215,8 +220,9 @@ TEST(ImageManager, OnStyleImageMissingBeforeSpriteLoaded) {
|
||||
|
||||
TEST(ImageManager, OnStyleImageMissingAfterSpriteLoaded) {
|
||||
util::RunLoop runLoop;
|
||||
ImageManager imageManager;
|
||||
StubImageRequestor requestor(imageManager);
|
||||
auto imageManagerPtr = std::make_shared<ImageManager>();
|
||||
auto& imageManager = *imageManagerPtr;
|
||||
StubImageRequestor requestor(imageManagerPtr);
|
||||
StubImageManagerObserver observer;
|
||||
|
||||
imageManager.setObserver(&observer);
|
||||
@@ -251,7 +257,8 @@ TEST(ImageManager, OnStyleImageMissingAfterSpriteLoaded) {
|
||||
|
||||
TEST(ImageManager, RemoveUnusedStyleImages) {
|
||||
util::RunLoop runLoop;
|
||||
ImageManager imageManager;
|
||||
auto imageManagerPtr = std::make_shared<ImageManager>();
|
||||
auto& imageManager = *imageManagerPtr;
|
||||
StubImageManagerObserver observer;
|
||||
imageManager.setObserver(&observer);
|
||||
imageManager.setLoaded(true);
|
||||
@@ -276,7 +283,7 @@ TEST(ImageManager, RemoveUnusedStyleImages) {
|
||||
|
||||
// Single requestor
|
||||
{
|
||||
std::unique_ptr<StubImageRequestor> requestor = std::make_unique<StubImageRequestor>(imageManager);
|
||||
std::unique_ptr<StubImageRequestor> requestor = std::make_unique<StubImageRequestor>(imageManagerPtr);
|
||||
imageManager.getImages(*requestor, std::make_pair(ImageDependencies{{"missing", ImageType::Icon}}, 0ull));
|
||||
runLoop.runOnce();
|
||||
EXPECT_EQ(observer.count, 1);
|
||||
@@ -296,7 +303,7 @@ TEST(ImageManager, RemoveUnusedStyleImages) {
|
||||
|
||||
// Single requestor, exceed cache size limit.
|
||||
{
|
||||
std::unique_ptr<StubImageRequestor> requestor = std::make_unique<StubImageRequestor>(imageManager);
|
||||
std::unique_ptr<StubImageRequestor> requestor = std::make_unique<StubImageRequestor>(imageManagerPtr);
|
||||
imageManager.getImages(*requestor, std::make_pair(ImageDependencies{{"1024px", ImageType::Icon}}, 0ull));
|
||||
runLoop.runOnce();
|
||||
EXPECT_EQ(observer.count, 2);
|
||||
@@ -311,8 +318,8 @@ TEST(ImageManager, RemoveUnusedStyleImages) {
|
||||
|
||||
// Multiple requestors
|
||||
{
|
||||
std::unique_ptr<StubImageRequestor> requestor1 = std::make_unique<StubImageRequestor>(imageManager);
|
||||
std::unique_ptr<StubImageRequestor> requestor2 = std::make_unique<StubImageRequestor>(imageManager);
|
||||
std::unique_ptr<StubImageRequestor> requestor1 = std::make_unique<StubImageRequestor>(imageManagerPtr);
|
||||
std::unique_ptr<StubImageRequestor> requestor2 = std::make_unique<StubImageRequestor>(imageManagerPtr);
|
||||
imageManager.getImages(*requestor1, std::make_pair(ImageDependencies{{"missing", ImageType::Icon}}, 0ull));
|
||||
imageManager.getImages(*requestor2, std::make_pair(ImageDependencies{{"missing", ImageType::Icon}}, 1ull));
|
||||
runLoop.runOnce();
|
||||
@@ -330,9 +337,9 @@ TEST(ImageManager, RemoveUnusedStyleImages) {
|
||||
|
||||
// Multiple requestors, check that image resource is not destroyed if there
|
||||
// is at least 1 requestor that uses it.
|
||||
std::unique_ptr<StubImageRequestor> requestor = std::make_unique<StubImageRequestor>(imageManager);
|
||||
std::unique_ptr<StubImageRequestor> requestor = std::make_unique<StubImageRequestor>(imageManagerPtr);
|
||||
{
|
||||
std::unique_ptr<StubImageRequestor> requestor1 = std::make_unique<StubImageRequestor>(imageManager);
|
||||
std::unique_ptr<StubImageRequestor> requestor1 = std::make_unique<StubImageRequestor>(imageManagerPtr);
|
||||
imageManager.getImages(
|
||||
*requestor,
|
||||
std::make_pair(ImageDependencies{{"missing", ImageType::Icon}, {"1024px", ImageType::Icon}}, 0ull));
|
||||
|
||||
@@ -62,8 +62,9 @@ public:
|
||||
TransformState transformState;
|
||||
Style style{fileSource, 1};
|
||||
AnnotationManager annotationManager{style};
|
||||
ImageManager imageManager;
|
||||
GlyphManager glyphManager;
|
||||
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
|
||||
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
|
||||
std::shared_ptr<Scheduler> threadPool = Scheduler::GetBackground();
|
||||
|
||||
TileParameters tileParameters(MapMode mapMode = MapMode::Continuous) {
|
||||
return {1.0,
|
||||
@@ -87,6 +88,8 @@ public:
|
||||
transformState = transform.getState();
|
||||
}
|
||||
|
||||
~SourceTest() { threadPool->waitForEmpty(); }
|
||||
|
||||
void run() { loop.run(); }
|
||||
|
||||
void end() { loop.stop(); }
|
||||
@@ -167,7 +170,7 @@ TEST(Source, RasterTileEmpty) {
|
||||
FAIL() << "Should never be called";
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -203,7 +206,7 @@ TEST(Source, RasterDEMTileEmpty) {
|
||||
FAIL() << "Should never be called";
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -241,7 +244,7 @@ TEST(Source, VectorTileEmpty) {
|
||||
FAIL() << "Should never be called";
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -276,7 +279,7 @@ TEST(Source, RasterTileFail) {
|
||||
test.end();
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -311,7 +314,7 @@ TEST(Source, RasterDEMTileFail) {
|
||||
test.end();
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -348,7 +351,7 @@ TEST(Source, VectorTileFail) {
|
||||
test.end();
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -384,7 +387,7 @@ TEST(Source, RasterTileCorrupt) {
|
||||
test.end();
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -421,7 +424,7 @@ TEST(Source, RasterDEMTileCorrupt) {
|
||||
test.end();
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -458,7 +461,7 @@ TEST(Source, VectorTileCorrupt) {
|
||||
test.end();
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -492,7 +495,7 @@ TEST(Source, RasterTileCancel) {
|
||||
FAIL() << "Should never be called";
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -526,7 +529,7 @@ TEST(Source, RasterDEMTileCancel) {
|
||||
FAIL() << "Should never be called";
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -562,7 +565,7 @@ TEST(Source, VectorTileCancel) {
|
||||
FAIL() << "Should never be called";
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -607,7 +610,7 @@ TEST(Source, RasterTileAttribution) {
|
||||
source.setObserver(&test.styleObserver);
|
||||
source.loadDescription(*test.fileSource);
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
test.run();
|
||||
@@ -648,7 +651,7 @@ TEST(Source, RasterDEMTileAttribution) {
|
||||
source.setObserver(&test.styleObserver);
|
||||
source.loadDescription(*test.fileSource);
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
test.run();
|
||||
@@ -741,7 +744,7 @@ TEST(Source, CustomGeometrySourceSetTileData) {
|
||||
FAIL() << "Should never be called";
|
||||
};
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
@@ -778,8 +781,8 @@ public:
|
||||
MOCK_METHOD1(tileSetNecessity, void(TileNecessity));
|
||||
MOCK_METHOD1(tileSetMinimumUpdateInterval, void(Duration));
|
||||
|
||||
explicit FakeTileSource(Immutable<style::Source::Impl> impl_)
|
||||
: RenderTileSetSource(std::move(impl_)) {}
|
||||
explicit FakeTileSource(Immutable<style::Source::Impl> impl_, std::shared_ptr<Scheduler> threadPool_)
|
||||
: RenderTileSetSource(std::move(impl_), std::move(threadPool_)) {}
|
||||
void updateInternal(const Tileset& tileset,
|
||||
const std::vector<Immutable<style::LayerProperties>>& layers,
|
||||
const bool needsRendering,
|
||||
@@ -816,7 +819,7 @@ TEST(Source, InvisibleSourcesTileNecessity) {
|
||||
VectorSource initialized("source", Tileset{{"tiles"}});
|
||||
initialized.loadDescription(*test.fileSource);
|
||||
|
||||
FakeTileSource renderTilesetSource{initialized.baseImpl};
|
||||
FakeTileSource renderTilesetSource{initialized.baseImpl, test.threadPool};
|
||||
RenderSource* renderSource = &renderTilesetSource;
|
||||
LineLayer layer("id", "source");
|
||||
Immutable<LayerProperties> layerProperties = makeMutable<LineLayerProperties>(
|
||||
@@ -839,7 +842,7 @@ TEST(Source, SourceMinimumUpdateInterval) {
|
||||
VectorSource initialized("source", Tileset{{"tiles"}});
|
||||
initialized.loadDescription(*test.fileSource);
|
||||
|
||||
FakeTileSource renderTilesetSource{initialized.baseImpl};
|
||||
FakeTileSource renderTilesetSource{initialized.baseImpl, test.threadPool};
|
||||
RenderSource* renderSource = &renderTilesetSource;
|
||||
LineLayer layer("id", "source");
|
||||
Immutable<LayerProperties> layerProperties = makeMutable<LineLayerProperties>(
|
||||
@@ -882,8 +885,8 @@ TEST(Source, RenderTileSetSourceUpdate) {
|
||||
|
||||
class FakeRenderTileSetSource : public RenderTileSetSource {
|
||||
public:
|
||||
explicit FakeRenderTileSetSource(Immutable<style::Source::Impl> impl_)
|
||||
: RenderTileSetSource(std::move(impl_)) {}
|
||||
explicit FakeRenderTileSetSource(Immutable<style::Source::Impl> impl_, std::shared_ptr<Scheduler> threadPool_)
|
||||
: RenderTileSetSource(std::move(impl_), std::move(threadPool_)) {}
|
||||
|
||||
MOCK_METHOD0(mockedUpdateInternal, void());
|
||||
|
||||
@@ -903,7 +906,7 @@ TEST(Source, RenderTileSetSourceUpdate) {
|
||||
VectorSource initialized("source", Tileset{{"tiles"}});
|
||||
initialized.loadDescription(*test.fileSource);
|
||||
|
||||
FakeRenderTileSetSource renderTilesetSource{initialized.baseImpl};
|
||||
FakeRenderTileSetSource renderTilesetSource{initialized.baseImpl, test.threadPool};
|
||||
|
||||
LineLayer layer("id", "source");
|
||||
Immutable<LayerProperties> layerProperties = makeMutable<LineLayerProperties>(
|
||||
@@ -969,7 +972,7 @@ TEST(Source, GeoJSONSourceTilesAfterDataReset) {
|
||||
auto geoJSONData = GeoJSONData::create(mapbox::geojson::parse(
|
||||
R"({"geometry": {"type": "Point", "coordinates": [1.1, 1.1]}, "type": "Feature", "properties": {}})"));
|
||||
source.setGeoJSONData(geoJSONData);
|
||||
RenderGeoJSONSource renderSource{staticImmutableCast<GeoJSONSource::Impl>(source.baseImpl)};
|
||||
RenderGeoJSONSource renderSource{staticImmutableCast<GeoJSONSource::Impl>(source.baseImpl), test.threadPool};
|
||||
|
||||
CircleLayer layer("id", "source");
|
||||
Immutable<LayerProperties> layerProperties = makeMutable<CircleLayerProperties>(
|
||||
@@ -1026,7 +1029,7 @@ TEST(Source, SetMaxParentOverscaleFactor) {
|
||||
ASSERT_EQ(3, *source.getMaxOverscaleFactorForParentTiles());
|
||||
source.loadDescription(*test.fileSource);
|
||||
|
||||
auto renderSource = RenderSource::create(source.baseImpl);
|
||||
auto renderSource = RenderSource::create(source.baseImpl, test.threadPool);
|
||||
renderSource->setObserver(&test.renderSourceObserver);
|
||||
renderSource->update(source.baseImpl, layers, true, true, test.tileParameters());
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ public:
|
||||
util::RunLoop loop;
|
||||
style::Style style{fileSource, 1};
|
||||
AnnotationManager annotationManager{style};
|
||||
ImageManager imageManager;
|
||||
GlyphManager glyphManager;
|
||||
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
|
||||
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
|
||||
|
||||
TileParameters tileParameters{1.0,
|
||||
MapDebugOptions(),
|
||||
|
||||
@@ -27,8 +27,8 @@ public:
|
||||
util::RunLoop loop;
|
||||
style::Style style{fileSource, 1};
|
||||
AnnotationManager annotationManager{style};
|
||||
ImageManager imageManager;
|
||||
GlyphManager glyphManager;
|
||||
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
|
||||
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
|
||||
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
|
||||
|
||||
TileParameters tileParameters{1.0,
|
||||
|
||||
@@ -21,8 +21,8 @@ public:
|
||||
util::RunLoop loop;
|
||||
style::Style style{fileSource, 1};
|
||||
AnnotationManager annotationManager{style};
|
||||
ImageManager imageManager;
|
||||
GlyphManager glyphManager;
|
||||
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
|
||||
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
|
||||
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
|
||||
|
||||
TileParameters tileParameters{1.0,
|
||||
|
||||
@@ -21,8 +21,8 @@ public:
|
||||
util::RunLoop loop;
|
||||
style::Style style{fileSource, 1};
|
||||
AnnotationManager annotationManager{style};
|
||||
ImageManager imageManager;
|
||||
GlyphManager glyphManager;
|
||||
std::shared_ptr<ImageManager> imageManager = std::make_shared<ImageManager>();
|
||||
std::shared_ptr<GlyphManager> glyphManager = std::make_shared<GlyphManager>();
|
||||
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
|
||||
|
||||
TileParameters tileParameters{1.0,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <mbgl/tile/vector_tile.hpp>
|
||||
#include <mbgl/tile/vector_tile_data.hpp>
|
||||
|
||||
#include <mbgl/actor/scheduler.hpp>
|
||||
#include <mbgl/annotation/annotation_manager.hpp>
|
||||
#include <mbgl/geometry/feature_index.hpp>
|
||||
#include <mbgl/map/transform.hpp>
|
||||
@@ -16,34 +17,16 @@
|
||||
#include <mbgl/renderer/tile_parameters.hpp>
|
||||
#include <mbgl/style/layers/symbol_layer.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/test/vector_tile_test.hpp>
|
||||
#include <mbgl/text/glyph_manager.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
#include <mbgl/util/identity.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
class VectorTileTest {
|
||||
public:
|
||||
std::shared_ptr<FileSource> fileSource = std::make_shared<FakeFileSource>();
|
||||
TransformState transformState;
|
||||
util::RunLoop loop;
|
||||
style::Style style{fileSource, 1};
|
||||
AnnotationManager annotationManager{style};
|
||||
ImageManager imageManager;
|
||||
GlyphManager glyphManager;
|
||||
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
|
||||
|
||||
TileParameters tileParameters{1.0,
|
||||
MapDebugOptions(),
|
||||
transformState,
|
||||
fileSource,
|
||||
MapMode::Continuous,
|
||||
annotationManager.makeWeakPtr(),
|
||||
imageManager,
|
||||
glyphManager,
|
||||
0};
|
||||
};
|
||||
namespace {
|
||||
|
||||
class VectorTileMock : public VectorTile {
|
||||
public:
|
||||
@@ -51,16 +34,20 @@ public:
|
||||
std::string sourceID_,
|
||||
const TileParameters& parameters,
|
||||
const Tileset& tileset)
|
||||
: VectorTile(id_, sourceID_, parameters, tileset) {
|
||||
: VectorTile(id_, std::move(sourceID_), parameters, tileset) {
|
||||
renderable = true;
|
||||
}
|
||||
|
||||
util::SimpleIdentity uniqueId;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(TileCache, Smoke) {
|
||||
VectorTileTest test;
|
||||
TileCache cache(1);
|
||||
OverscaledTileID id(0, 0, 0);
|
||||
std::unique_ptr<Tile> tile = std::make_unique<VectorTileMock>(id, "source", test.tileParameters, test.tileset);
|
||||
TileCache cache(Scheduler::GetBackground(), 1);
|
||||
const OverscaledTileID id(0, 0, 0);
|
||||
auto tile = std::make_unique<VectorTileMock>(id, "source", test.tileParameters, test.tileset);
|
||||
|
||||
cache.add(id, std::move(tile));
|
||||
EXPECT_TRUE(cache.has(id));
|
||||
@@ -70,18 +57,36 @@ TEST(TileCache, Smoke) {
|
||||
|
||||
TEST(TileCache, Issue15926) {
|
||||
VectorTileTest test;
|
||||
TileCache cache(2);
|
||||
OverscaledTileID id0(0, 0, 0);
|
||||
OverscaledTileID id1(1, 0, 0);
|
||||
std::unique_ptr<Tile> tile1 = std::make_unique<VectorTileMock>(id0, "source", test.tileParameters, test.tileset);
|
||||
std::unique_ptr<Tile> tile2 = std::make_unique<VectorTileMock>(id0, "source", test.tileParameters, test.tileset);
|
||||
std::unique_ptr<Tile> tile3 = std::make_unique<VectorTileMock>(id1, "source", test.tileParameters, test.tileset);
|
||||
TileCache cache(test.threadPool, 2);
|
||||
const OverscaledTileID id0(0, 0, 0);
|
||||
const OverscaledTileID id1(1, 0, 0);
|
||||
auto tile1 = std::make_unique<VectorTileMock>(id0, "source", test.tileParameters, test.tileset);
|
||||
auto tile2 = std::make_unique<VectorTileMock>(id0, "source", test.tileParameters, test.tileset);
|
||||
auto tile3 = std::make_unique<VectorTileMock>(id1, "source", test.tileParameters, test.tileset);
|
||||
auto tile4 = std::make_unique<VectorTileMock>(id0, "source", test.tileParameters, test.tileset);
|
||||
const auto tile1Id = tile1->uniqueId;
|
||||
|
||||
// add
|
||||
cache.add(id0, std::move(tile1));
|
||||
EXPECT_TRUE(cache.has(id0));
|
||||
|
||||
// adding a key already present doesn't replace the existing item
|
||||
cache.add(id0, std::move(tile2));
|
||||
EXPECT_EQ(tile1Id, static_cast<VectorTileMock*>(cache.get(id0))->uniqueId);
|
||||
|
||||
// Evict on add
|
||||
cache.setSize(1);
|
||||
cache.add(id1, std::move(tile3));
|
||||
EXPECT_FALSE(cache.has(id0));
|
||||
EXPECT_TRUE(cache.has(id1));
|
||||
|
||||
// Evict due to size limit change
|
||||
cache.setSize(2);
|
||||
cache.add(id0, std::move(tile4));
|
||||
EXPECT_TRUE(cache.has(id0));
|
||||
EXPECT_TRUE(cache.has(id1));
|
||||
cache.setSize(1);
|
||||
// older item should be evicted
|
||||
EXPECT_TRUE(cache.has(id0));
|
||||
EXPECT_FALSE(cache.has(id1));
|
||||
}
|
||||
|
||||
@@ -15,35 +15,13 @@
|
||||
#include <mbgl/geometry/feature_index.hpp>
|
||||
#include <mbgl/annotation/annotation_manager.hpp>
|
||||
#include <mbgl/renderer/image_manager.hpp>
|
||||
#include <mbgl/test/vector_tile_test.hpp>
|
||||
#include <mbgl/text/glyph_manager.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
class VectorTileTest {
|
||||
public:
|
||||
std::shared_ptr<FileSource> fileSource = std::make_shared<FakeFileSource>(ResourceOptions::Default(),
|
||||
ClientOptions());
|
||||
TransformState transformState;
|
||||
util::RunLoop loop;
|
||||
style::Style style{fileSource, 1};
|
||||
AnnotationManager annotationManager{style};
|
||||
ImageManager imageManager;
|
||||
GlyphManager glyphManager;
|
||||
Tileset tileset{{"https://example.com"}, {0, 22}, "none"};
|
||||
|
||||
TileParameters tileParameters{1.0,
|
||||
MapDebugOptions(),
|
||||
transformState,
|
||||
fileSource,
|
||||
MapMode::Continuous,
|
||||
annotationManager.makeWeakPtr(),
|
||||
imageManager,
|
||||
glyphManager,
|
||||
0};
|
||||
};
|
||||
|
||||
TEST(VectorTile, setError) {
|
||||
VectorTileTest test;
|
||||
VectorTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, test.tileset);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <mbgl/actor/actor_ref.hpp>
|
||||
#include <mbgl/actor/scheduler.hpp>
|
||||
#include <mbgl/platform/settings.hpp>
|
||||
#include <mbgl/test/util.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
#include <mbgl/util/timer.hpp>
|
||||
@@ -134,6 +135,11 @@ TEST(Thread, Concurrency) {
|
||||
unsigned numMessages = 100000;
|
||||
std::atomic_uint completed(numMessages);
|
||||
|
||||
auto& settings = platform::Settings::getInstance();
|
||||
if (!settings.get(platform::EXPERIMENTAL_THREAD_PRIORITY_WORKER).getDouble()) {
|
||||
settings.set(platform::EXPERIMENTAL_THREAD_PRIORITY_WORKER, 0.5);
|
||||
}
|
||||
|
||||
Actor<TestWorker> poolWorker(Scheduler::GetBackground());
|
||||
auto poolWorkerRef = poolWorker.self();
|
||||
|
||||
@@ -328,3 +334,108 @@ TEST(Thread, DeleteBeforeChildStarts) {
|
||||
// Should process the queue before destruction.
|
||||
ASSERT_TRUE(flag);
|
||||
}
|
||||
|
||||
TEST(Thread, PoolWait) {
|
||||
auto pool = Scheduler::GetBackground();
|
||||
|
||||
constexpr int threadCount = 10;
|
||||
for (int i = 0; i < threadCount; ++i) {
|
||||
pool->schedule([&] { std::this_thread::sleep_for(Milliseconds(100)); });
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, pool->waitForEmpty());
|
||||
}
|
||||
|
||||
TEST(Thread, PoolWaitRecursiveAdd) {
|
||||
auto pool = Scheduler::GetBackground();
|
||||
|
||||
pool->schedule([&] {
|
||||
// Scheduled tasks can add more tasks
|
||||
pool->schedule([&] {
|
||||
std::this_thread::sleep_for(Milliseconds(10));
|
||||
pool->schedule([&] { std::this_thread::sleep_for(Milliseconds(10)); });
|
||||
});
|
||||
std::this_thread::sleep_for(Milliseconds(10));
|
||||
});
|
||||
|
||||
EXPECT_EQ(0, pool->waitForEmpty());
|
||||
}
|
||||
|
||||
TEST(Thread, PoolWaitAdd) {
|
||||
auto pool = Scheduler::GetBackground();
|
||||
auto seq = Scheduler::GetSequenced();
|
||||
|
||||
// add new tasks every few milliseconds
|
||||
std::atomic<bool> addActive{true};
|
||||
std::atomic<int> added{0};
|
||||
std::atomic<int> executed{0};
|
||||
seq->schedule([&] {
|
||||
while (addActive) {
|
||||
pool->schedule([&] { executed++; });
|
||||
added++;
|
||||
}
|
||||
});
|
||||
|
||||
// Wait be sure some are added
|
||||
while (added < 1) {
|
||||
std::this_thread::sleep_for(Milliseconds(10));
|
||||
}
|
||||
|
||||
// Add an item that should take long enough to be confident that
|
||||
// more items would be added by the sequential task if not blocked
|
||||
pool->schedule([&] { std::this_thread::sleep_for(Milliseconds(100)); });
|
||||
|
||||
EXPECT_EQ(0, pool->waitForEmpty());
|
||||
|
||||
addActive = false;
|
||||
EXPECT_EQ(0, pool->waitForEmpty());
|
||||
}
|
||||
|
||||
TEST(Thread, PoolWaitTimeout) {
|
||||
auto pool = Scheduler::GetBackground();
|
||||
|
||||
std::mutex mutex;
|
||||
{
|
||||
std::lock_guard<std::mutex> outerLock(mutex);
|
||||
pool->schedule([&] { std::lock_guard<std::mutex> innerLock(mutex); });
|
||||
|
||||
// should always time out
|
||||
EXPECT_EQ(1, pool->waitForEmpty(Milliseconds(100)));
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, pool->waitForEmpty());
|
||||
}
|
||||
|
||||
TEST(Thread, PoolWaitException) {
|
||||
auto pool = Scheduler::GetBackground();
|
||||
|
||||
std::atomic<int> caught{0};
|
||||
pool->setExceptionHandler([&](const auto) { caught++; });
|
||||
|
||||
constexpr int threadCount = 3;
|
||||
for (int i = 0; i < threadCount; ++i) {
|
||||
pool->schedule([=] {
|
||||
std::this_thread::sleep_for(Milliseconds(i));
|
||||
if (i & 1) {
|
||||
throw std::runtime_error("test");
|
||||
} else {
|
||||
throw 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Exceptions shouldn't cause deadlocks by, e.g., abandoning locks.
|
||||
EXPECT_EQ(0, pool->waitForEmpty());
|
||||
EXPECT_EQ(threadCount, caught);
|
||||
}
|
||||
|
||||
#if defined(NDEBUG)
|
||||
TEST(Thread, WrongThread) {
|
||||
auto pool = Scheduler::GetBackground();
|
||||
|
||||
// Asserts in debug builds, silently ignored in release.
|
||||
pool->schedule([&] { EXPECT_EQ(0, pool->waitForEmpty()); });
|
||||
|
||||
EXPECT_EQ(0, pool->waitForEmpty());
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user