-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[core, ios] Improve performance of queryRenderedFeatures by reducing # of temp GeometryCollection #15183
[core, ios] Improve performance of queryRenderedFeatures by reducing # of temp GeometryCollection #15183
Changes from all commits
4f2cc3a
90b4314
ed3ef82
1844b9c
43c695b
b7ee698
1380f12
c21f06f
47310ea
f923e91
9624904
8ebc0d6
a3f7bfd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,8 @@ | |
#import "../src/MGLMapView_Experimental.h" | ||
|
||
#import <objc/runtime.h> | ||
#import <os/log.h> | ||
#import <os/signpost.h> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. iosapp is larded down and we’ve been trying to trim it back — since this logging functionality could presumably be useful in other/future view controllers, can we move this stuff out into a separate file? |
||
|
||
static const CLLocationCoordinate2D WorldTourDestinations[] = { | ||
{ .latitude = 38.8999418, .longitude = -77.033996 }, | ||
|
@@ -63,6 +65,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsAnnotationsRows) { | |
MBXSettingsAnnotationsTestShapes, | ||
MBXSettingsAnnotationsCustomCallout, | ||
MBXSettingsAnnotationsQueryAnnotations, | ||
MBXSettingsAnnotationsQueryRoadsAroundDC, | ||
MBXSettingsAnnotationsCustomUserDot, | ||
MBXSettingsAnnotationsRemoveAnnotations, | ||
MBXSettingsAnnotationSelectRandomOffscreenPointAnnotation, | ||
|
@@ -215,10 +218,36 @@ @interface MBXViewController () <UITableViewDelegate, | |
@property (nonatomic) NSMutableArray<UIWindow *> *helperWindows; | ||
@property (nonatomic) NSMutableArray<UIView *> *contentInsetsOverlays; | ||
|
||
@property (nonatomic) os_log_t log; | ||
@property (nonatomic) os_signpost_id_t signpost; | ||
@property (nonatomic) NSMutableArray<dispatch_block_t> *pendingIdleBlocks; | ||
|
||
@end | ||
|
||
#define OS_SIGNPOST_BEGIN_WITH_SELF(self, name) \ | ||
if (@available(iOS 12.0, *)) { os_signpost_interval_begin(self.log, self.signpost, name); } | ||
|
||
#define OS_SIGNPOST_END_WITH_SELF(self, name) \ | ||
if (@available(iOS 12.0, *)) { os_signpost_interval_end(self.log, self.signpost, name); } | ||
|
||
#define OS_SIGNPOST_BEGIN(name) \ | ||
OS_SIGNPOST_BEGIN_WITH_SELF(self, name) | ||
|
||
#define OS_SIGNPOST_END(name) \ | ||
OS_SIGNPOST_END_WITH_SELF(self, name) | ||
|
||
#define OS_SIGNPOST_EVENT(name, ...) \ | ||
if (@available(iOS 12.0, *)) { os_signpost_event_emit(self.log, self.signpost, name, ##__VA_ARGS__); } | ||
|
||
// Expose properties for testing | ||
@interface MGLMapView (MBXViewController) | ||
@property (nonatomic) NSDictionary *annotationViewReuseQueueByIdentifier; | ||
- (void)setNeedsRerender; | ||
- (UIEdgeInsets)defaultEdgeInsetsForShowAnnotations; | ||
@end | ||
|
||
@interface MGLStyle (MBXViewController) | ||
@property (nonatomic, readonly, copy) NSArray<MGLVectorStyleLayer *> *roadStyleLayers; | ||
@end | ||
|
||
@implementation MBXViewController | ||
|
@@ -234,6 +263,12 @@ - (void)viewDidLoad | |
{ | ||
[super viewDidLoad]; | ||
|
||
self.pendingIdleBlocks = [NSMutableArray array]; | ||
self.log = os_log_create("com.mapbox.iosapp", "MBXViewController"); | ||
if (@available(iOS 12.0, *)) { | ||
self.signpost = os_signpost_id_generate(self.log); | ||
} | ||
|
||
// Keep track of current map state and debug preferences, | ||
// saving and restoring when the application's state changes. | ||
self.currentState = [MBXStateManager sharedManager].currentState; | ||
|
@@ -390,6 +425,7 @@ - (void)dismissSettings:(__unused id)sender | |
@"Add Test Shapes", | ||
@"Add Point With Custom Callout", | ||
@"Query Annotations", | ||
@"Query Roads around DC", | ||
[NSString stringWithFormat:@"%@ Custom User Dot", (_customUserLocationAnnnotationEnabled ? @"Disable" : @"Enable")], | ||
@"Remove Annotations", | ||
@"Select an offscreen point annotation", | ||
|
@@ -520,22 +556,22 @@ - (void)performActionForSettingAtIndexPath:(NSIndexPath *)indexPath | |
switch (indexPath.row) | ||
{ | ||
case MBXSettingsAnnotations100Views: | ||
[self parseFeaturesAddingCount:100 usingViews:YES]; | ||
[self parseFeaturesAddingCount:100 usingViews:YES completionHandler:NULL]; | ||
break; | ||
case MBXSettingsAnnotations1000Views: | ||
[self parseFeaturesAddingCount:1000 usingViews:YES]; | ||
[self parseFeaturesAddingCount:1000 usingViews:YES completionHandler:NULL]; | ||
break; | ||
case MBXSettingsAnnotations10000Views: | ||
[self parseFeaturesAddingCount:10000 usingViews:YES]; | ||
[self parseFeaturesAddingCount:10000 usingViews:YES completionHandler:NULL]; | ||
break; | ||
case MBXSettingsAnnotations100Sprites: | ||
[self parseFeaturesAddingCount:100 usingViews:NO]; | ||
[self parseFeaturesAddingCount:100 usingViews:NO completionHandler:NULL]; | ||
break; | ||
case MBXSettingsAnnotations1000Sprites: | ||
[self parseFeaturesAddingCount:1000 usingViews:NO]; | ||
[self parseFeaturesAddingCount:1000 usingViews:NO completionHandler:NULL]; | ||
break; | ||
case MBXSettingsAnnotations10000Sprites: | ||
[self parseFeaturesAddingCount:10000 usingViews:NO]; | ||
[self parseFeaturesAddingCount:10000 usingViews:NO completionHandler:NULL]; | ||
break; | ||
case MBXSettingsAnnotationAnimation: | ||
[self animateAnnotationView]; | ||
|
@@ -549,6 +585,25 @@ - (void)performActionForSettingAtIndexPath:(NSIndexPath *)indexPath | |
case MBXSettingsAnnotationsQueryAnnotations: | ||
[self testQueryPointAnnotations]; | ||
break; | ||
|
||
case MBXSettingsAnnotationsQueryRoadsAroundDC: | ||
{ | ||
__weak __typeof__(self) weakSelf = self; | ||
[self parseFeaturesAddingCount:100 usingViews:YES completionHandler:^{ | ||
[weakSelf.mapView setNeedsRerender]; | ||
[weakSelf.pendingIdleBlocks addObject:^{ | ||
__typeof__(self) strongSelf = weakSelf; | ||
NSLog(@"BEGIN: query-roads-batch"); | ||
OS_SIGNPOST_BEGIN_WITH_SELF(strongSelf, "query-roads-batch"); | ||
for (int i = 0; i < 10; i++) { | ||
[strongSelf queryRoads]; | ||
} | ||
OS_SIGNPOST_END_WITH_SELF(strongSelf, "query-roads-batch"); | ||
NSLog(@"END: query-roads-batch"); | ||
}]; | ||
}]; | ||
} | ||
break; | ||
case MBXSettingsAnnotationsCustomUserDot: | ||
[self toggleCustomUserDot]; | ||
break; | ||
|
@@ -815,7 +870,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath | |
|
||
#pragma mark - Debugging Actions | ||
|
||
- (void)parseFeaturesAddingCount:(NSUInteger)featuresCount usingViews:(BOOL)useViews | ||
- (void)parseFeaturesAddingCount:(NSUInteger)featuresCount usingViews:(BOOL)useViews completionHandler:(nullable dispatch_block_t)completion | ||
{ | ||
[self.mapView removeAnnotations:self.mapView.annotations]; | ||
|
||
|
@@ -850,7 +905,11 @@ - (void)parseFeaturesAddingCount:(NSUInteger)featuresCount usingViews:(BOOL)useV | |
dispatch_async(dispatch_get_main_queue(), ^ | ||
{ | ||
[self.mapView addAnnotations:annotations]; | ||
[self.mapView showAnnotations:annotations animated:YES]; | ||
UIEdgeInsets insets = [self.mapView defaultEdgeInsetsForShowAnnotations]; | ||
[self.mapView showAnnotations:annotations | ||
edgePadding:insets | ||
animated:YES | ||
completionHandler:completion]; | ||
}); | ||
} | ||
}); | ||
|
@@ -1765,6 +1824,21 @@ - (NSString *)telemetryDebugLogFilePath | |
return filePath; | ||
} | ||
|
||
#pragma mark - Query Rendered Features | ||
|
||
- (void)queryRoads | ||
{ | ||
OS_SIGNPOST_BEGIN("query-roads"); | ||
|
||
NSArray *roadStyleLayerIdentifiers = [self.mapView.style.roadStyleLayers valueForKey:@"identifier"]; | ||
NSArray *visibleRoadFeatures = [self.mapView visibleFeaturesInRect:self.mapView.bounds inStyleLayersWithIdentifiers:[NSSet setWithArray:roadStyleLayerIdentifiers]]; | ||
|
||
OS_SIGNPOST_END("query-roads"); | ||
OS_SIGNPOST_EVENT("query-roads-count", "%lu", (unsigned long)visibleRoadFeatures.count); | ||
|
||
NSLog(@"Roads & labels feature count: %lu", (unsigned long)visibleRoadFeatures.count); | ||
} | ||
|
||
#pragma mark - Random World Tour | ||
|
||
- (void)addAnnotations:(NSInteger)numAnnotations aroundCoordinate:(CLLocationCoordinate2D)coordinate radius:(CLLocationDistance)radius { | ||
|
@@ -1989,6 +2063,7 @@ - (IBAction)cycleStyles:(__unused id)sender | |
} | ||
} | ||
} | ||
free(methods); | ||
NSAssert(numStyleURLMethods == styleNames.count, | ||
@"MGLStyle provides %u default styles but iosapp only knows about %lu of them.", | ||
numStyleURLMethods, (unsigned long)styleNames.count); | ||
|
@@ -2047,6 +2122,16 @@ - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIVi | |
|
||
#pragma mark - MGLMapViewDelegate | ||
|
||
- (void)mapViewDidBecomeIdle:(MGLMapView *)mapView | ||
{ | ||
NSArray *blocks = [self.pendingIdleBlocks copy]; | ||
[self.pendingIdleBlocks removeAllObjects]; | ||
|
||
for (dispatch_block_t block in blocks) { | ||
block(); | ||
} | ||
} | ||
|
||
- (MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id<MGLAnnotation>)annotation | ||
{ | ||
if (annotation == mapView.userLocation) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -214,14 +214,16 @@ void RenderLineLayer::render(PaintParameters& parameters) { | |
} | ||
} | ||
|
||
optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const double offset) { | ||
if (offset == 0) return {}; | ||
std::unique_ptr<GeometryCollection> offsetLine(const GeometryCollection& rings, const double offset) { | ||
|
||
if (offset == 0) return nullptr; | ||
|
||
std::unique_ptr<GeometryCollection> newRings = std::make_unique<GeometryCollection>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After some checks I came to conclusion that we could keep the old semantics with the
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha - will test out. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Another option is to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hm, another issue could be that we have two return statements that could prevent RVO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
in this case we're creating an instance of another type: |
||
|
||
GeometryCollection newRings; | ||
Point<double> zero(0, 0); | ||
for (const auto& ring : rings) { | ||
newRings.emplace_back(); | ||
auto& newRing = newRings.back(); | ||
newRings->emplace_back(); | ||
auto& newRing = newRings->back(); | ||
|
||
for (auto i = ring.begin(); i != ring.end(); i++) { | ||
auto& p = *i; | ||
|
@@ -237,7 +239,7 @@ optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const d | |
const double cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y; | ||
extrude *= (1.0 / cosHalfAngle); | ||
|
||
newRing.push_back(convertPoint<int16_t>(extrude * offset) + p); | ||
newRing.emplace_back(convertPoint<int16_t>(extrude * offset) + p); | ||
} | ||
} | ||
|
||
|
@@ -247,6 +249,7 @@ optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const d | |
bool RenderLineLayer::queryIntersectsFeature( | ||
const GeometryCoordinates& queryGeometry, | ||
const GeometryTileFeature& feature, | ||
const GeometryCollection& geometries, | ||
const float zoom, | ||
const TransformState& transformState, | ||
const float pixelsToTileUnits, | ||
|
@@ -265,13 +268,14 @@ bool RenderLineLayer::queryIntersectsFeature( | |
.evaluate(feature, zoom, style::LineOffset::defaultValue()) * pixelsToTileUnits; | ||
|
||
// Apply offset to geometry | ||
auto offsetGeometry = offsetLine(feature.getGeometries(), offset); | ||
auto offsetGeometry = offsetLine(geometries, offset); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. const auto& offsetGeometry = offsetLine(geometries, offset); |
||
|
||
// Test intersection | ||
const float halfWidth = getLineWidth(feature, zoom) / 2.0 * pixelsToTileUnits; | ||
|
||
return util::polygonIntersectsBufferedMultiLine( | ||
translatedQueryGeometry.value_or(queryGeometry), | ||
offsetGeometry.value_or(feature.getGeometries()), | ||
offsetGeometry != nullptr ? *offsetGeometry : geometries, | ||
halfWidth); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
focused? 😄 I've never used focussed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UK English ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If even the Europeans are against you... 😅
In any case, this also struck me as wrong. I think we should stick with ‘merican English, given our audience/company/etc.
Alternatively: