diff options
author | Julian Rex <julian.rex@mapbox.com> | 2018-03-22 14:58:54 -0400 |
---|---|---|
committer | Julian Rex <julian.rex@mapbox.com> | 2018-03-22 14:58:54 -0400 |
commit | 7556299851d8ba7067500369545af4d2aa5b4c77 (patch) | |
tree | 9fbfeb38cf5a7a36b1e5963c8b423679c54f69aa | |
parent | bcdf23028e93a8216fc6b877486a04ac5a579c58 (diff) | |
download | qtlocation-mapboxgl-7556299851d8ba7067500369545af4d2aa5b4c77.tar.gz |
WIP - adds a new object that retains/releases the MGLOpenGLLayer through callbacks.
-rw-r--r-- | include/mbgl/style/layer.hpp | 2 | ||||
-rw-r--r-- | include/mbgl/style/layers/custom_layer.hpp | 34 | ||||
-rw-r--r-- | platform/darwin/src/MGLOpenGLStyleLayer.h | 18 | ||||
-rw-r--r-- | platform/darwin/src/MGLOpenGLStyleLayer.mm | 194 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyle.mm | 12 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyleLayerRetentionManager.mm | 53 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyleLayerRetentionManager_Private.h | 16 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyle_Private.h | 5 | ||||
-rw-r--r-- | platform/ios/Integration Tests/MBGLIntegrationTests.mm | 128 | ||||
-rw-r--r-- | platform/ios/ios.xcodeproj/project.pbxproj | 12 | ||||
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 13 | ||||
-rw-r--r-- | platform/ios/src/MGLMapView_Private.h | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_custom_layer.cpp | 12 | ||||
-rw-r--r-- | src/mbgl/style/layers/custom_layer.cpp | 44 | ||||
-rw-r--r-- | src/mbgl/style/layers/custom_layer_impl.cpp | 47 | ||||
-rw-r--r-- | src/mbgl/style/layers/custom_layer_impl.hpp | 13 |
16 files changed, 415 insertions, 190 deletions
diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index 12494f5387..259fb30b6d 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -127,7 +127,7 @@ public: virtual std::unique_ptr<Layer> cloneRef(const std::string& id) const = 0; LayerObserver* observer = nullptr; - void setObserver(LayerObserver*); + virtual void setObserver(LayerObserver*); // For use in SDK bindings, which store a reference to a platform-native peer // object here, so that separately-obtained references to this object share diff --git a/include/mbgl/style/layers/custom_layer.hpp b/include/mbgl/style/layers/custom_layer.hpp index cd54c54ffb..05d12f47f4 100644 --- a/include/mbgl/style/layers/custom_layer.hpp +++ b/include/mbgl/style/layers/custom_layer.hpp @@ -54,16 +54,12 @@ using CustomLayerContextLostFunction = void (*)(void* context); */ using CustomLayerDeinitializeFunction = void (*)(void* context); -/** - * Called from `CustomLayer`'s destructor. - * This provides a mechanism to handle any necessary clean-up using the provided `peer` object. - * For example, if a platform-native peer object has a raw pointer to the CustomLayer it could be - * set to NULL. - * - * This function is called from CustomLayer, unlike the above functions that are passed into the - * private implementation. - */ -using CustomLayerDeallocationFunction = void (*)(util::unique_any *peer); + + +using CustomLayerContextOwnerChangedFunction = void (*)(void* context, void* owner); +using CustomLayerContextAttachFunction = void (*)(void* context); +using CustomLayerContextDetachFunction = void (*)(void* context); + class CustomLayer : public Layer { public: @@ -72,14 +68,22 @@ public: CustomLayerRenderFunction, CustomLayerContextLostFunction, CustomLayerDeinitializeFunction, - CustomLayerDeallocationFunction, + + // Wrap these 4? + CustomLayerContextOwnerChangedFunction, + CustomLayerContextAttachFunction, + CustomLayerContextDetachFunction, void* context); CustomLayer(const std::string& id, CustomLayerInitializeFunction, CustomLayerRenderFunction, CustomLayerDeinitializeFunction, - CustomLayerDeallocationFunction, + + // Wrap these 4? + CustomLayerContextOwnerChangedFunction, + CustomLayerContextAttachFunction, + CustomLayerContextDetachFunction, void* context); ~CustomLayer() final; @@ -96,12 +100,14 @@ public: class Impl; const Impl& impl() const; + const void* getContext() const; + + void setObserver(LayerObserver* observer); + Mutable<Impl> mutableImpl() const; std::unique_ptr<Layer> cloneRef(const std::string& id) const final; CustomLayer(const CustomLayer&) = delete; - - CustomLayerDeallocationFunction deallocationFn = nullptr; }; template <> diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.h b/platform/darwin/src/MGLOpenGLStyleLayer.h index 0b494e8062..52173786f7 100644 --- a/platform/darwin/src/MGLOpenGLStyleLayer.h +++ b/platform/darwin/src/MGLOpenGLStyleLayer.h @@ -10,6 +10,21 @@ NS_ASSUME_NONNULL_BEGIN @class MGLMapView; @class MGLStyle; +@class MGLOpenGLStyleLayer; + +MGL_EXPORT +@interface MGLOpenGLStyleLayerRetainer: NSObject +@property (nonatomic, weak, readonly) MGLOpenGLStyleLayer *layer; +@property (nonatomic, assign, readonly) NSInteger layerRetainCount; +@property (nonatomic, unsafe_unretained, nullable) void *owner; +- (instancetype)initWithLayer:(MGLStyleLayer*)styleLayer; +- (void)retainLayer; +- (void)weakenLayer; +@end + + + + typedef struct MGLStyleLayerDrawingContext { CGSize size; CLLocationCoordinate2D centerCoordinate; @@ -21,9 +36,10 @@ typedef struct MGLStyleLayerDrawingContext { MGL_EXPORT @interface MGLOpenGLStyleLayer : MGLStyleLayer - @property (nonatomic, weak, readonly) MGLStyle *style; +- (BOOL)isBeingManaged; + - (instancetype)initWithIdentifier:(NSString *)identifier; - (void)didMoveToMapView:(MGLMapView *)mapView; diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm index a5f8b574a0..2b638e2067 100644 --- a/platform/darwin/src/MGLOpenGLStyleLayer.mm +++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm @@ -7,6 +7,96 @@ #include <mbgl/style/layers/custom_layer.hpp> #include <mbgl/math/wrap.hpp> +@interface MGLOpenGLStyleLayerRetainer () +@property (nonatomic, weak, readwrite) MGLOpenGLStyleLayer *layer; +@property (nonatomic, assign, readwrite) NSInteger layerRetainCount; +@end + +@implementation MGLOpenGLStyleLayerRetainer + +- (void)dealloc { + NSLog(@"LayerRetainer dealloc start %p", self); + + while (self.layerRetainCount) { + [self weakenLayer]; + } + + NSLog(@"LayerRetainer dealloc end %p", self); +} + +- (instancetype)initWithLayer:(MGLOpenGLStyleLayer*)styleLayer { + if ((self = [super init])) { + _layer = styleLayer; + } + NSLog(@"LayerRetainer %p init with layer %p", self, styleLayer); + return self; +} + +- (void)setOwner:(nullable void *)owner { + void* oldOwner = _owner; + + _owner = owner; + + if (oldOwner) { + NSLog(@"LayerRetainer %p released", self); + CFBridgingRelease((__bridge CFTypeRef)(self)); + } + + if (_owner) { + NSLog(@"LayerRetainer %p retained", self); + CFBridgingRetain(self); + } +} + +- (void)retainLayer { + + if (!self.layer) + return; + + NSAssert(self.layerRetainCount >= 0, @""); + + @autoreleasepool { + CFBridgingRetain(self.layer); + } + self.layerRetainCount++; + + NSLog(@"LayerRetainer %p strengthen %ld", self, self.layerRetainCount); +} + + +- (void)weakenLayer { + if (!self.layer) + return; + + NSAssert(self.layerRetainCount > 0, @""); + + self.layerRetainCount--; + + @autoreleasepool { + CFBridgingRelease((__bridge CFTypeRef)self.layer); + } + + NSLog(@"LayerRetainer %p weaken %ld", self, self.layerRetainCount); +} +@end + +void MGLCustomLayerContextOwnerChangedFunction(void *context, void* owner) { + MGLOpenGLStyleLayerRetainer *contextRetainer = (__bridge MGLOpenGLStyleLayerRetainer*)context; + contextRetainer.owner = owner; +} + +void MGLCustomLayerContextAttachFunction(void *context) { + MGLOpenGLStyleLayerRetainer *contextRetainer = (__bridge MGLOpenGLStyleLayerRetainer*)context; + [contextRetainer retainLayer]; +} + +void MGLCustomLayerContextDetachFunction(void *context) { + MGLOpenGLStyleLayerRetainer *contextRetainer = (__bridge MGLOpenGLStyleLayerRetainer*)context; + [contextRetainer weakenLayer]; +} + + + /** Runs the preparation handler block contained in the given context, which is implicitly an instance of `MGLOpenGLStyleLayer`. @@ -17,7 +107,10 @@ void MGLPrepareCustomStyleLayer(void *context) { // Note, that the layer is retained/released by MGLStyle, ensuring that the layer // is alive during rendering - MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer*)context; +// MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer*)context; + + MGLOpenGLStyleLayerRetainer *retainer = (__bridge MGLOpenGLStyleLayerRetainer*)context; + MGLOpenGLStyleLayer *layer = retainer.layer; [layer didMoveToMapView:layer.style.mapView]; } @@ -30,7 +123,15 @@ void MGLPrepareCustomStyleLayer(void *context) { when creating an OpenGL style layer. */ void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRenderParameters ¶ms) { - MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context; +// MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context; + MGLOpenGLStyleLayer *layer = ((__bridge MGLOpenGLStyleLayerRetainer*)context).layer; + + if (!layer) + { + NSLog(@"no layer"); + return; + } + MGLStyleLayerDrawingContext drawingContext = { .size = CGSizeMake(params.width, params.height), .centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude), @@ -52,7 +153,9 @@ void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRender void MGLFinishCustomStyleLayer(void *context) { // Note, that the layer is retained/released by MGLStyle, ensuring that the layer // is alive during rendering - MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer*)context; +// MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer*)context; + MGLOpenGLStyleLayerRetainer *retainer = (__bridge MGLOpenGLStyleLayerRetainer*)context; + MGLOpenGLStyleLayer *layer = retainer.layer; [layer willMoveFromMapView:layer.style.mapView]; } @@ -62,29 +165,29 @@ void MGLFinishCustomStyleLayer(void *context) { Function to be called when the core `CustomLayer` (not the Impl) gets deallocated. It's possible taht at this stage the Obj-C style layer is being deallocated (but that case is detected). */ -void MGLDeallocateCustomStyleLayer(mbgl::util::unique_any *peer) { - - // We know that the peer object contains a LayerWrapper with a weak pointer to - // our custom layer. We can use this to safely access the layer, and clear out the - // raw pointer. - // - // If we don't do this rawLayer can become a dangling pointer (which was previously being - // accessed via the description method) - - if (!(peer && peer->has_value())) - return; - - LayerWrapper *wrapper = mbgl::util::any_cast<LayerWrapper>(peer); - - if (!wrapper) - return; - - // If the MGLStyleLayer is currently being dealloc'd (and trigger the CustomLayer destructor, and - // this function) then layer here will be nil (even though wrapper->layer may appear to be non-nil) - MGLStyleLayer *layer = wrapper->layer; - - layer.rawLayer = NULL; -} +//void MGLDeallocateCustomStyleLayer(mbgl::util::unique_any *peer) { +// +// // We know that the peer object contains a LayerWrapper with a weak pointer to +// // our custom layer. We can use this to safely access the layer, and clear out the +// // raw pointer. +// // +// // If we don't do this rawLayer can become a dangling pointer (which was previously being +// // accessed via the description method) +// +// if (!(peer && peer->has_value())) +// return; +// +// LayerWrapper *wrapper = mbgl::util::any_cast<LayerWrapper>(peer); +// +// if (!wrapper) +// return; +// +// // If the MGLStyleLayer is currently being dealloc'd (and trigger the CustomLayer destructor, and +// // this function) then layer here will be nil (even though wrapper->layer may appear to be non-nil) +// MGLStyleLayer *layer = wrapper->layer; +// +// layer.rawLayer = NULL; +//} /** @@ -132,14 +235,45 @@ void MGLDeallocateCustomStyleLayer(mbgl::util::unique_any *peer) { which it is added. @return An initialized OpenGL style layer. */ + +- (BOOL)isBeingManaged { + if (self.rawLayer == NULL) { + return NO; + } + + auto customLayer = self.rawLayer->template as<mbgl::style::CustomLayer>(); + + if (!customLayer) { + return NO; + } + + MGLOpenGLStyleLayerRetainer *retainer = (__bridge MGLOpenGLStyleLayerRetainer*)(customLayer->getContext()); + + return retainer.layerRetainCount > 0; +} + +- (void)dealloc +{ + NSLog(@"MGLOpenGLStyleLayer dealloc %p\n", self); +} + - (instancetype)initWithIdentifier:(NSString *)identifier { + + NSLog(@"MGLOpenGLStyleLayer init %p\n", self); + + MGLOpenGLStyleLayerRetainer *retainer = [[MGLOpenGLStyleLayerRetainer alloc] initWithLayer:self]; + // Note, do not retain self here, otherwise MGLOpenGLStyleLayer will never be dealloc'd auto layer = std::make_unique<mbgl::style::CustomLayer>(identifier.UTF8String, MGLPrepareCustomStyleLayer, MGLDrawCustomStyleLayer, MGLFinishCustomStyleLayer, - MGLDeallocateCustomStyleLayer, - (__bridge void*)self); + + MGLCustomLayerContextOwnerChangedFunction, + MGLCustomLayerContextAttachFunction, + MGLCustomLayerContextDetachFunction, + + (__bridge void*)retainer); return self = [super initWithPendingLayer:std::move(layer)]; } @@ -163,7 +297,7 @@ void MGLDeallocateCustomStyleLayer(mbgl::util::unique_any *peer) { // We need to ensure that this layer is retained, so that any references from layer impl's // e.g. contexts) are still valid - [style addToManagedLayers:self]; +// [style addToManagedLayers:self]; [super addToStyle:style belowLayer:otherLayer]; } @@ -173,7 +307,7 @@ void MGLDeallocateCustomStyleLayer(mbgl::util::unique_any *peer) { // We need to ensure that this layer is now released (however, if this layer is about to be // used by the renderer then it will released once rendering is complete) - [style removeFromManagedLayers:self]; +// [style removeFromManagedLayers:self]; self.style = nil; } diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index 3d503d77aa..f6fc5533be 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -84,7 +84,6 @@ @property (nonatomic, readonly) mbgl::style::Style *rawStyle; @property (readonly, copy, nullable) NSURL *URL; @property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, NS_DICTIONARY_OF(NSObject *, MGLTextLanguage *) *) *localizedLayersByIdentifier; -@property (nonatomic, readwrite) NSMutableSet *managedLayers; @end @@ -173,7 +172,6 @@ static NSURL *MGLStyleURL_trafficNight; - (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView { if (self = [super init]) { - _managedLayers = [NSMutableSet set]; _mapView = mapView; _rawStyle = rawStyle; _localizedLayersByIdentifier = [NSMutableDictionary dictionary]; @@ -536,16 +534,6 @@ static NSURL *MGLStyleURL_trafficNight; [self didChangeValueForKey:@"layers"]; } -#pragma mark - Layer retain/release management - -- (void)addToManagedLayers:(MGLStyleLayer*)layer { - [self.managedLayers addObject:layer]; -} - -- (void)removeFromManagedLayers:(MGLStyleLayer*)layer { - [self.managedLayers removeObject:layer]; -} - #pragma mark Style classes - (NS_ARRAY_OF(NSString *) *)styleClasses diff --git a/platform/darwin/src/MGLStyleLayerRetentionManager.mm b/platform/darwin/src/MGLStyleLayerRetentionManager.mm deleted file mode 100644 index 71ebd574ad..0000000000 --- a/platform/darwin/src/MGLStyleLayerRetentionManager.mm +++ /dev/null @@ -1,53 +0,0 @@ -#import "MGLStyle.h" -#import "MGLStyleLayer.h" -#import "MGLStyleLayerRetentionManager_Private.h" -#include <mbgl/style/style.hpp> -#include <mbgl/style/layers/custom_layer.hpp> - -static const NSUInteger MGLStyleLayerRetentionManagerCapacityHint = 100; - -@interface MGLStyleLayerRetentionManager () -@property (nonatomic) NSMapTable<MGLStyleLayer*, NSNumber*> *retentionTable; -@end - -@implementation MGLStyleLayerRetentionManager - -- (instancetype)init { - if ((self = [super init])) { - _retentionTable = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory|NSPointerFunctionsObjectPointerPersonality - valueOptions:NSPointerFunctionsStrongMemory - capacity:MGLStyleLayerRetentionManagerCapacityHint]; - } - return self; -} - -- (BOOL)isManagedLayer:(nullable MGLStyleLayer*)styleLayer { - return [self.retentionTable objectForKey:styleLayer] != nil; -} - -- (void)updateRetainedLayers:(nonnull NSSet<MGLStyleLayer*>*)sourceObjects { - - // Add/update the objects from the source set, with a default lifetime - for (id layer in sourceObjects) { - [self.retentionTable setObject:@(MGLStyleLayerRetentionManagerDefaultLifetime) forKey:layer]; - } -} - -- (void)decrementLifetimes { - // Consider double-buffering the two tables, so we don't keep allocing/deallocing tables. - NSMapTable *retentionTable = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory|NSPointerFunctionsObjectPointerPersonality - valueOptions:NSPointerFunctionsStrongMemory - capacity:MGLStyleLayerRetentionManagerCapacityHint]; - - for (MGLStyleLayer *layer in self.retentionTable) { - NSInteger lifeTime = [[self.retentionTable objectForKey:layer] integerValue]; - - if (lifeTime > 0) { - [retentionTable setObject:@(lifeTime - 1) forKey:layer]; - } - } - - self.retentionTable = retentionTable; -} - -@end diff --git a/platform/darwin/src/MGLStyleLayerRetentionManager_Private.h b/platform/darwin/src/MGLStyleLayerRetentionManager_Private.h deleted file mode 100644 index 0063d342a5..0000000000 --- a/platform/darwin/src/MGLStyleLayerRetentionManager_Private.h +++ /dev/null @@ -1,16 +0,0 @@ -@class MGLStyle; - -static const NSInteger MGLStyleLayerRetentionManagerDefaultLifetime = 2; - -/** - Object use to manage the retain/release of `MGLStyleLayer`s (currently only `MGLOpenGLStyleLayer`. - Managed layers are given a "lifetime", and this is reset everytime `-updateRetainedLayers:` is called. - The lifetime is decremented with each call to `-decrementLifetimes`, when it reaches 0 the layer - is removed from the manager (potentially releasing it) - */ -@interface MGLStyleLayerRetentionManager : NSObject -- (BOOL)isManagedLayer:(nullable MGLStyleLayer*)styleLayer; -- (void)updateRetainedLayers:(nonnull NSSet<MGLStyleLayer*>*)sourceObjects; -- (void)decrementLifetimes; -@end - diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h index 00985403f5..55a84f432f 100644 --- a/platform/darwin/src/MGLStyle_Private.h +++ b/platform/darwin/src/MGLStyle_Private.h @@ -23,14 +23,13 @@ namespace mbgl { @property (nonatomic, readonly, weak) MGLMapView *mapView; @property (nonatomic, readonly) mbgl::style::Style *rawStyle; -@property (nonatomic, readonly) NSMutableSet *managedLayers; - (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor; - (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration; -- (void)addToManagedLayers:(MGLStyleLayer*)layer; -- (void)removeFromManagedLayers:(MGLStyleLayer*)layer; +//- (void)addToManagedLayers:(MGLStyleLayer*)layer; +//- (void)removeFromManagedLayers:(MGLStyleLayer*)layer; @end @interface MGLStyle (MGLStreetsAdditions) diff --git a/platform/ios/Integration Tests/MBGLIntegrationTests.mm b/platform/ios/Integration Tests/MBGLIntegrationTests.mm index 5e390bb8e6..2e01ce8ca2 100644 --- a/platform/ios/Integration Tests/MBGLIntegrationTests.mm +++ b/platform/ios/Integration Tests/MBGLIntegrationTests.mm @@ -2,10 +2,12 @@ #import <objc/message.h> #import <Mapbox/Mapbox.h> -#import "src/MGLStyleLayerRetentionManager_Private.h" #import "src/MGLStyleLayer_Private.h" #import "../ios/src/MGLMapView_Private.h" +#define TRACE(message) NSLog(@"%@: %@", NSStringFromSelector(_cmd), message) + + @interface MBGLIntegrationTests : XCTestCase <MGLMapViewDelegate> @property (nonatomic) MGLMapView *mapView; @@ -70,14 +72,17 @@ } - (void)waitForManagedLayersToExpire { - NSInteger count = MGLStyleLayerRetentionManagerDefaultLifetime; - while (count--) { - [self waitForMapViewToBeRendered]; - } + // NSInteger count = MGLStyleLayerRetentionManagerDefaultLifetime; + // while (count--) { + [self waitForMapViewToBeRendered]; + // } } - (BOOL)isLayerBeingManaged:(MGLStyleLayer*)layer { - return [self.mapView debugIsStyleLayerBeingManaged:layer]; + + MGLOpenGLStyleLayer *glLayer = [layer isKindOfClass:[MGLOpenGLStyleLayer class]] ? (MGLOpenGLStyleLayer*)layer : nil; + + return [glLayer isBeingManaged]; } - (MGLStyle *)style { @@ -86,6 +91,108 @@ #pragma mark - Tests + +- (void)testLayerRetainer { + + __weak MGLOpenGLStyleLayer *weaklayer1 = nil; + __weak MGLOpenGLStyleLayerRetainer *weakLayerRetainer = nil; + __unsafe_unretained MGLOpenGLStyleLayer *unsafelayer1 = nil; + + + // For test purposes, we look at the retain count, but for this to make any + // sense we also need to use unsafe unretained (to stop the call from retaining + // the very value we're intereested in. We also use autorelease pools. Do + // NOT use this in production code!!! + SEL retainCountSelector = NSSelectorFromString(@"retainCount"); + NSInteger (*retainCount)(id, SEL) = (NSInteger (*)(id, SEL))objc_msgSend; + + #define ASSERT_RETAIN_COUNT(object, expectedCount) { \ + NSInteger count = retainCount(object, retainCountSelector); \ + XCTAssert(count == (expectedCount), @"Expected retain count mismatch for %s. Expected %d, got %ld", #object, expectedCount, count); \ + } + + + + @autoreleasepool { + + // Setup + TRACE(@"MGLOpenGLStyleLayer allocation:"); + MGLOpenGLStyleLayer *layer1 = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"test"]; + weaklayer1 = layer1; + unsafelayer1 = layer1; + + ASSERT_RETAIN_COUNT(unsafelayer1, 1); + + // First check to ensure a retainer gets released + { + TRACE(@"testing retainer dealloc"); + + @autoreleasepool { + MGLOpenGLStyleLayerRetainer *layerRetainer = [[MGLOpenGLStyleLayerRetainer alloc] initWithLayer:layer1]; + weakLayerRetainer = layerRetainer; + } + + XCTAssertNil(weakLayerRetainer); + } + + // Second check to check setting/unsetting owner + { + TRACE(@"testing retainer dealloc, after setting/clearing owner"); + + @autoreleasepool { + MGLOpenGLStyleLayerRetainer *layerRetainer = [[MGLOpenGLStyleLayerRetainer alloc] initWithLayer:layer1]; + weakLayerRetainer = layerRetainer; + layerRetainer.owner = (__bridge void*)self; + } + XCTAssertNotNil(weakLayerRetainer); + weakLayerRetainer.owner = NULL; + XCTAssertNil(weakLayerRetainer); + } + + // Now test "retaining" (used by layer during render & adding to style) + @autoreleasepool { + TRACE(@"testing retaining"); + + // Create a retainer + MGLOpenGLStyleLayerRetainer *layerRetainer = [[MGLOpenGLStyleLayerRetainer alloc] initWithLayer:layer1]; + weakLayerRetainer = layerRetainer; + + ASSERT_RETAIN_COUNT(unsafelayer1, 1); + + layerRetainer.owner = (__bridge void*)self; + + ASSERT_RETAIN_COUNT(unsafelayer1, 1); + + [layerRetainer retainLayer]; + + ASSERT_RETAIN_COUNT(unsafelayer1, 2); + } + + ASSERT_RETAIN_COUNT(unsafelayer1, 2); + + // Get rid of the layer, but we should still hold on to it via our + // retainer. + layer1 = nil; + } + + XCTAssertNotNil(weaklayer1); + XCTAssertNotNil(weakLayerRetainer); + + @autoreleasepool { + XCTAssertNotNil(weakLayerRetainer.layer); + } + + ASSERT_RETAIN_COUNT(unsafelayer1, 1); + + weakLayerRetainer.owner = NULL; + + XCTAssertNil(weakLayerRetainer); + XCTAssertNil(weaklayer1); + + #undef ASSERT_RETAIN_COUNT +} + + - (void)testStoringOpenGLLayerInCollections { // If we change the meaning of equality for MGLStyleLayer we want to know about it - since we // store layers in both a NSMutableSet and in a NSMapTable @@ -307,7 +414,7 @@ - (void)testOpenGLLayerDoesNotLeakWhenRemovedFromStyle { -// MGLOpenGLStyleLayer *layer; + // MGLOpenGLStyleLayer *layer; __weak id weakLayer; @autoreleasepool { MGLOpenGLStyleLayer *layer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"gl-layer"]; @@ -328,9 +435,10 @@ XCTAssert([self isLayerBeingManaged:weakLayer]); [self waitForMapViewToBeRendered]; - XCTAssertNotNil(weakLayer); - XCTAssert([self isLayerBeingManaged:weakLayer]); - [self waitForMapViewToBeRendered]; + + // XCTAssertNotNil(weakLayer); + // XCTAssert([self isLayerBeingManaged:weakLayer]); + // [self waitForMapViewToBeRendered]; XCTAssertNotNil(weakLayer); XCTAssert(![self isLayerBeingManaged:weakLayer]); diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index ff1d447f78..bea9787192 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -311,10 +311,6 @@ CA67C7FB204CFC9000C1CBB4 /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; }; CA67C7FD204CFCAA00C1CBB4 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA67C7FC204CFCAA00C1CBB4 /* UIKit.framework */; }; CA7F25182048841E00896957 /* polyline.geojson in Resources */ = {isa = PBXBuildFile; fileRef = DA1DC96D1CB6C6CE006E619F /* polyline.geojson */; }; - CA8F66E62049DD2900B5B9DC /* MGLStyleLayerRetentionManager_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CA8F66E42049DD2900B5B9DC /* MGLStyleLayerRetentionManager_Private.h */; }; - CA8F66E72049DD2900B5B9DC /* MGLStyleLayerRetentionManager_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CA8F66E42049DD2900B5B9DC /* MGLStyleLayerRetentionManager_Private.h */; }; - CA8F66E82049DD2900B5B9DC /* MGLStyleLayerRetentionManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8F66E52049DD2900B5B9DC /* MGLStyleLayerRetentionManager.mm */; }; - CA8F66E92049DD2900B5B9DC /* MGLStyleLayerRetentionManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8F66E52049DD2900B5B9DC /* MGLStyleLayerRetentionManager.mm */; }; CAAD2BD62041EF05003881EC /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; }; CAAD2BD72041EF05003881EC /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DA00FC8E1D5EEB0D009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -875,8 +871,6 @@ AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLTelemetryConfig.m; sourceTree = "<group>"; }; CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCameraChangeReason.h; sourceTree = "<group>"; }; CA67C7FC204CFCAA00C1CBB4 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - CA8F66E42049DD2900B5B9DC /* MGLStyleLayerRetentionManager_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayerRetentionManager_Private.h; sourceTree = "<group>"; }; - CA8F66E52049DD2900B5B9DC /* MGLStyleLayerRetentionManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLStyleLayerRetentionManager.mm; sourceTree = "<group>"; }; DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = "<group>"; }; DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = "<group>"; }; DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = "<group>"; }; @@ -1625,8 +1619,6 @@ DA8847EE1CBAFA5100AB86E3 /* MGLTypes.h */, DA8848111CBAFA6200AB86E3 /* MGLTypes.m */, 35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */, - CA8F66E42049DD2900B5B9DC /* MGLStyleLayerRetentionManager_Private.h */, - CA8F66E52049DD2900B5B9DC /* MGLStyleLayerRetentionManager.mm */, ); name = Foundation; path = ../darwin/src; @@ -1939,7 +1931,6 @@ 9654C1261FFC1AB900DB6A19 /* MGLPolyline_Private.h in Headers */, 40F887701D7A1E58008ECB67 /* MGLShapeSource_Private.h in Headers */, 350098DC1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.h in Headers */, - CA8F66E62049DD2900B5B9DC /* MGLStyleLayerRetentionManager_Private.h in Headers */, DA8848231CBAFA6200AB86E3 /* MGLOfflineStorage_Private.h in Headers */, 404326891D5B9B27007111BD /* MGLAnnotationContainerView_Private.h in Headers */, CA55CD41202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */, @@ -2138,7 +2129,6 @@ DABFB8651CBE99E500D62B32 /* MGLOverlay.h in Headers */, 35E79F211D41266300957B9E /* MGLStyleLayer_Private.h in Headers */, 350098DD1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.h in Headers */, - CA8F66E72049DD2900B5B9DC /* MGLStyleLayerRetentionManager_Private.h in Headers */, DABFB8681CBE99E500D62B32 /* MGLPolyline.h in Headers */, 96E516DF200054FB00A02306 /* MGLShape_Private.h in Headers */, DABFB86F1CBE9A0F00D62B32 /* MGLMapView.h in Headers */, @@ -2710,7 +2700,6 @@ 404C26E41D89B877000AA13D /* MGLTileSource.mm in Sources */, 07D947541F67489200E37934 /* MGLAbstractShapeSource.mm in Sources */, 355AE0011E9281DA00F3939D /* MGLScaleBar.mm in Sources */, - CA8F66E82049DD2900B5B9DC /* MGLStyleLayerRetentionManager.mm in Sources */, DA88481D1CBAFA6200AB86E3 /* MGLMapCamera.mm in Sources */, DACA86282019218600E9693A /* MGLRasterDEMSource.mm in Sources */, DA8848261CBAFA6200AB86E3 /* MGLPolygon.mm in Sources */, @@ -2804,7 +2793,6 @@ 355AE0021E9281DA00F3939D /* MGLScaleBar.mm in Sources */, 4018B1C81CDC287F00F666AF /* MGLAnnotationView.mm in Sources */, 07D8C6FB1F67560100381808 /* MGLComputedShapeSource.mm in Sources */, - CA8F66E92049DD2900B5B9DC /* MGLStyleLayerRetentionManager.mm in Sources */, DAA4E4341CBB730400178DFB /* MGLFaux3DUserLocationAnnotationView.m in Sources */, DACA86292019218600E9693A /* MGLRasterDEMSource.mm in Sources */, 35B82BFB1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */, diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 91121670a2..0db0488063 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -65,7 +65,6 @@ #import "MGLScaleBar.h" #import "MGLStyle_Private.h" #import "MGLStyleLayer_Private.h" -#import "MGLStyleLayerRetentionManager_Private.h" #import "MGLMapboxEvents.h" #import "MGLSDKUpdateChecker.h" #import "MGLCompactCalloutView.h" @@ -201,8 +200,6 @@ public: @property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints; @property (nonatomic, readwrite) MGLStyle *style; -@property (nonatomic) MGLStyleLayerRetentionManager* styleLayerRetentionManager; - @property (nonatomic) UITapGestureRecognizer *singleTapGestureRecognizer; @property (nonatomic) UITapGestureRecognizer *doubleTap; @@ -395,8 +392,6 @@ public: [self createGLView]; } - _styleLayerRetentionManager = [[MGLStyleLayerRetentionManager alloc] init]; - // setup accessibility // // self.isAccessibilityElement = YES; @@ -5561,8 +5556,6 @@ public: return; } - [self.styleLayerRetentionManager updateRetainedLayers:self.style.managedLayers]; - if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingFrame:)]) { [self.delegate mapViewWillStartRenderingFrame:self]; @@ -5581,7 +5574,6 @@ public: } [self updateAnnotationViews]; [self updateCalloutView]; - [self.styleLayerRetentionManager decrementLifetimes]; if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingFrame:fullyRendered:)]) { @@ -6358,9 +6350,4 @@ private: self.showsUserHeadingIndicator = showsHeading; } -- (BOOL)debugIsStyleLayerBeingManaged:(MGLStyleLayer*)layer { - return [self.styleLayerRetentionManager isManagedLayer:layer]; -} - - @end diff --git a/platform/ios/src/MGLMapView_Private.h b/platform/ios/src/MGLMapView_Private.h index 00900c9ef2..ca26af84a1 100644 --- a/platform/ios/src/MGLMapView_Private.h +++ b/platform/ios/src/MGLMapView_Private.h @@ -28,6 +28,4 @@ extern const CGSize MGLAnnotationAccessibilityElementMinimumSize; /** Empties the in-memory tile cache. */ - (void)didReceiveMemoryWarning; -/** Debug method, used in testing, to check if a layer's retain/release is being managed */ -- (BOOL)debugIsStyleLayerBeingManaged:(MGLStyleLayer*)layer; @end diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp index adafd8583f..eab87b19c5 100644 --- a/src/mbgl/renderer/layers/render_custom_layer.cpp +++ b/src/mbgl/renderer/layers/render_custom_layer.cpp @@ -22,6 +22,8 @@ RenderCustomLayer::~RenderCustomLayer() { } else if (!contextDestroyed && impl().deinitializeFn) { impl().deinitializeFn(impl().context); } + + impl().detachFn(impl().context); } } @@ -47,10 +49,20 @@ void RenderCustomLayer::render(PaintParameters& paintParameters, RenderSource*) //If the context changed, deinitialize the previous one before initializing the new one. if (context && !contextDestroyed && impl().deinitializeFn) { impl().deinitializeFn(context); + + if (impl().detachFn) { + impl().detachFn(context); + } } context = impl().context; + + if (impl().attachFn) { + impl().attachFn(context); + } + assert(impl().initializeFn); impl().initializeFn(impl().context); + initialized = true; } diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp index 40013f3422..3198173412 100644 --- a/src/mbgl/style/layers/custom_layer.cpp +++ b/src/mbgl/style/layers/custom_layer.cpp @@ -5,37 +5,50 @@ namespace mbgl { namespace style { +CustomLayer::~CustomLayer() +{ + printf("~CustomLayer destructor %p\n", this); + +} + CustomLayer::CustomLayer(const std::string& layerID, CustomLayerInitializeFunction init, CustomLayerRenderFunction render, CustomLayerContextLostFunction contextLost, CustomLayerDeinitializeFunction deinit, - CustomLayerDeallocationFunction deallocation, + + CustomLayerContextOwnerChangedFunction ownerChanged, + CustomLayerContextAttachFunction attach, + CustomLayerContextDetachFunction detach, void* context) - : Layer(makeMutable<Impl>(layerID, init, render, contextLost, deinit, context)), - deallocationFn(deallocation) { + : Layer(makeMutable<Impl>(layerID, init, render, contextLost, deinit, ownerChanged, attach, detach, context)) +{ + printf("CustomLayer::CustomLayer %p\n", this); + } CustomLayer::CustomLayer(const std::string& layerID, CustomLayerInitializeFunction init, CustomLayerRenderFunction render, CustomLayerDeinitializeFunction deinit, - CustomLayerDeallocationFunction deallocation, + + CustomLayerContextOwnerChangedFunction ownerChanged, + CustomLayerContextAttachFunction attach, + CustomLayerContextDetachFunction detach, void* context) - : Layer(makeMutable<Impl>(layerID, init, render, nullptr, deinit, context)), - deallocationFn(deallocation) { + : Layer(makeMutable<Impl>(layerID, init, render, nullptr, deinit, ownerChanged, attach, detach, context)) +{ + printf("CustomLayer::CustomLayer %p\n", this); } -CustomLayer::~CustomLayer() { - if (deallocationFn) { - deallocationFn(&peer); - } -}; - const CustomLayer::Impl& CustomLayer::impl() const { return static_cast<const Impl&>(*baseImpl); } +const void* CustomLayer::getContext() const { + return impl().context; +} + Mutable<CustomLayer::Impl> CustomLayer::mutableImpl() const { return makeMutable<Impl>(impl()); } @@ -45,6 +58,13 @@ std::unique_ptr<Layer> CustomLayer::cloneRef(const std::string&) const { return nullptr; } +void CustomLayer::setObserver(LayerObserver* observer) { + + Layer::setObserver(observer); + + impl().didSetObserver(observer != NULL); +} + // Visibility void CustomLayer::setVisibility(VisibilityType value) { diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp index 1de268d2e2..5d1e1f6ab5 100644 --- a/src/mbgl/style/layers/custom_layer_impl.cpp +++ b/src/mbgl/style/layers/custom_layer_impl.cpp @@ -3,18 +3,43 @@ namespace mbgl { namespace style { +CustomLayer::Impl::~Impl() { + if (changeOwnerFn) + changeOwnerFn(context, NULL); +} + CustomLayer::Impl::Impl(const std::string& id_, - CustomLayerInitializeFunction initializeFn_, - CustomLayerRenderFunction renderFn_, - CustomLayerContextLostFunction contextLostFn_, - CustomLayerDeinitializeFunction deinitializeFn_, - void* context_) - : Layer::Impl(LayerType::Custom, id_, std::string()) { - initializeFn = initializeFn_; - renderFn = renderFn_; - deinitializeFn = deinitializeFn_; - contextLostFn = contextLostFn_; - context = context_; + CustomLayerInitializeFunction initializeFn_, + CustomLayerRenderFunction renderFn_, + CustomLayerContextLostFunction contextLostFn_, + CustomLayerDeinitializeFunction deinitializeFn_, + + CustomLayerContextOwnerChangedFunction changeOwnerFn_, + CustomLayerContextAttachFunction attachFn_, + CustomLayerContextDetachFunction detachFn_, + + void* context_): + Layer::Impl(LayerType::Custom, id_, std::string()), + initializeFn(initializeFn_), + renderFn(renderFn_), + contextLostFn(contextLostFn_), + deinitializeFn(deinitializeFn_), + changeOwnerFn(changeOwnerFn_), + attachFn(attachFn_), + detachFn(detachFn_), + context(context_) { + + if (changeOwnerFn) + changeOwnerFn(context, this); +} + +void CustomLayer::Impl::didSetObserver(bool didSet) const { + if (didSet) { + if (attachFn) attachFn(context); + } + else { + if (detachFn) detachFn(context); + } } bool CustomLayer::Impl::hasLayoutDifference(const Layer::Impl&) const { diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp index 62efbbe15b..6bc23f0759 100644 --- a/src/mbgl/style/layers/custom_layer_impl.hpp +++ b/src/mbgl/style/layers/custom_layer_impl.hpp @@ -11,11 +11,17 @@ namespace style { class CustomLayer::Impl : public Layer::Impl { public: + virtual ~Impl(); + Impl(const std::string& id, CustomLayerInitializeFunction, CustomLayerRenderFunction, CustomLayerContextLostFunction, CustomLayerDeinitializeFunction, + + CustomLayerContextOwnerChangedFunction, + CustomLayerContextAttachFunction, + CustomLayerContextDetachFunction, void* context); bool hasLayoutDifference(const Layer::Impl&) const override; @@ -25,7 +31,14 @@ public: CustomLayerRenderFunction renderFn = nullptr; CustomLayerContextLostFunction contextLostFn = nullptr; CustomLayerDeinitializeFunction deinitializeFn = nullptr; + + CustomLayerContextOwnerChangedFunction changeOwnerFn = nullptr; + CustomLayerContextAttachFunction attachFn = nullptr; + CustomLayerContextDetachFunction detachFn = nullptr; + void* context = nullptr; + + void didSetObserver(bool didSet) const; }; } // namespace style |