Skip to content

Commit

Permalink
Expose tileCacheBudget on Sources (#2003)
Browse files Browse the repository at this point in the history
* MAPSIOS-1142 & MAPSIOS-1143 expose tile-cache-budget

* Update docs

* Add additional test and documentation

* Update to address review

* Update for tests/documentation

* Address review

* Update SLA metrics

* Update naming and address review

* Update Tests
  • Loading branch information
pjleonard37 authored Feb 1, 2024
1 parent 3feb203 commit 942afd6
Show file tree
Hide file tree
Showing 28 changed files with 239 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Use them to configure respective map options after creating a map view.
* Introduce experimental `MapboxMap.collectPerformanceStatistics` allowing to collect map rendering performance statistics, both for UIKit and SwiftUI.
* Bump Turf version to `2.8.0`.
* Bump minimum Xcode version to `14.3.1`.
* Introduce `tileCacheBudget` property on `GeoJsonSource`, `RasterSource`, `RasterDemSource`, `RasterArraySource`, `VectorSource`, `CustomGeometrySource`, and `CustomRasterSource`. This property defines a source-specific resource budget (`TileCacheBudgetSize`). When reached, the least recently used tile will be evicted from the cache. `MapboxMaps/setTileCacheBudget(size:)` will now use the `TileCacheBudgetSize` property, the older method with `TileCacheBudget` has been deprecated and will be removed in a future major release.

## 11.1.0 - 17 January, 2024

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
- ``CustomRasterSource``
- ``CustomRasterSourceOptions``
- ``TileFunctionCallback``
- ``TileCacheBudgetSize``
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ While maintaing the existing gesture approach we made minor improvements. In v11

#### 2.12.7 Cache Management

Experimental API `MapboxMap/setMemoryBudget(_:)` was renamed to ``MapboxMap/setTileCacheBudget(_:)`` and promoted to stable.
Experimental API `MapboxMap/setMemoryBudget(_:)` was renamed to ``MapboxMap/setTileCacheBudget(size:)`` and promoted to stable.

#### 2.12.8 Puck3D's scaling behavior

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
### Prefetching

- ``MapboxMap/prefetchZoomDelta``
- ``MapboxMap/setTileCacheBudget(_:)``
- ``MapboxMap/setTileCacheBudget(size:)``
- ``MapboxMap/shouldRenderWorldCopies``
- ``MapboxMap/elevation(at:)``

Expand Down
18 changes: 17 additions & 1 deletion Sources/MapboxMaps/Foundation/MapboxMap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,25 @@ public final class MapboxMap: StyleManager {
/// If tile cache budget in megabytes is set, the engine will try to use ETC1 texture compression
/// for raster layers, therefore, raster images with alpha channel will be rendered incorrectly.
///
/// If null is set, the tile cache budget size in tile units will be dynamically calculated based on
/// the current viewport size.
/// - Parameter size: The tile cache budget size to be used by the Map.
public func setTileCacheBudget(size: TileCacheBudgetSize?) {
__map.__setTileCacheBudgetFor(size?.coreTileCacheBudget)
}

/// The MapboxCoreMaps tile cache budget hint to be used by the map.
///
/// The budget can be given in tile units or in megabytes. A Map will do the best effort to keep memory
/// allocations for a non essential resources within the budget.
///
/// If tile cache budget in megabytes is set, the engine will try to use ETC1 texture compression
/// for raster layers, therefore, raster images with alpha channel will be rendered incorrectly.
///
/// If null is set, the tile cache budget in tile units will be dynamically calculated based on
/// the current viewport size.
/// - Parameter tileCacheBudget: The tile cache budget hint to be used by the Map.
/// - Parameter tileCacheBudget: The MapboxCoreMaps tile cache budget hint to be used by the Map.
@available(*, deprecated, message: "Use .setTileCacheBudget(size: TileCacheBudgetSize?) instead.")
public func setTileCacheBudget(_ tileCacheBudget: TileCacheBudget?) {
__map.__setTileCacheBudgetFor(tileCacheBudget)
}
Expand Down
26 changes: 24 additions & 2 deletions Sources/MapboxMaps/Style/CustomSources/CustomGeometrySource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ public struct CustomGeometrySource: Source {
/// Settings for the custom geometry, including a fetchTileFunction callback
public let options: CustomGeometrySourceOptions?

/// This property defines a source-specific resource budget, either in tile units or in megabytes. Whenever the tile cache goes over the defined limit, the least recently used tile will be evicted from the in-memory cache.
/// - Note: Current implementation does not take into account resources allocated by the visible tiles.
public var tileCacheBudget: TileCacheBudgetSize?

public init(id: String, options: CustomGeometrySourceOptions) {
self.type = .customGeometry
self.id = id
Expand All @@ -26,20 +30,38 @@ extension CustomGeometrySource {
enum CodingKeys: String, CodingKey {
case id
case type
case tileCacheBudget = "tile-cache-budget"
}

/// Init from a decoder, note that the CustomGeometrySourceOptions are not decodable and need to be set separately
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
type = try container.decode(SourceType.self, forKey: .type)
tileCacheBudget = try container.decodeIfPresent(TileCacheBudgetSize.self, forKey: .tileCacheBudget)
options = nil
}

/// Encode, note that options will not be included
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(type, forKey: .type)

if encoder.userInfo[.volatilePropertiesOnly] as? Bool == true {
try encodeVolatile(to: encoder, into: &container)
} else if encoder.userInfo[.nonVolatilePropertiesOnly] as? Bool == true {
try encodeNonVolatile(to: encoder, into: &container)
} else {
try encodeVolatile(to: encoder, into: &container)
try encodeNonVolatile(to: encoder, into: &container)
}
}

private func encodeVolatile(to encoder: Encoder, into container: inout KeyedEncodingContainer<CodingKeys>) throws {
try container.encodeIfPresent(tileCacheBudget, forKey: .tileCacheBudget)
}

private func encodeNonVolatile(to encoder: Encoder, into container: inout KeyedEncodingContainer<CodingKeys>) throws {
try container.encodeIfPresent(id, forKey: .id)
try container.encodeIfPresent(type, forKey: .type)
}
}
28 changes: 26 additions & 2 deletions Sources/MapboxMaps/Style/CustomSources/CustomRasterSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public struct CustomRasterSource: Source {
#endif
public let options: CustomRasterSourceOptions?

/// This property defines a source-specific resource budget, either in tile units or in megabytes. Whenever the tile cache goes over the defined limit, the least recently used tile will be evicted from the in-memory cache. Note that the current implementation does not take into account resources allocated by the visible tiles.
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
public var tileCacheBudget: TileCacheBudgetSize?

#if swift(>=5.8)
@_documentation(visibility: public)
#endif
Expand All @@ -40,19 +46,37 @@ extension CustomRasterSource {
enum CodingKeys: String, CodingKey {
case id
case type
case tileCacheBudget = "tile-cache-budget"
}

/// Init from a decoder, note that the CustomRasterSourceOptions are not decodable and need to be set separately
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
tileCacheBudget = try container.decodeIfPresent(TileCacheBudgetSize.self, forKey: .tileCacheBudget)
options = nil
}

/// Encode, note that options will not be included
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(type, forKey: .type)

if encoder.userInfo[.volatilePropertiesOnly] as? Bool == true {
try encodeVolatile(to: encoder, into: &container)
} else if encoder.userInfo[.nonVolatilePropertiesOnly] as? Bool == true {
try encodeNonVolatile(to: encoder, into: &container)
} else {
try encodeVolatile(to: encoder, into: &container)
try encodeNonVolatile(to: encoder, into: &container)
}
}

private func encodeVolatile(to encoder: Encoder, into container: inout KeyedEncodingContainer<CodingKeys>) throws {
try container.encodeIfPresent(tileCacheBudget, forKey: .tileCacheBudget)
}

private func encodeNonVolatile(to encoder: Encoder, into container: inout KeyedEncodingContainer<CodingKeys>) throws {
try container.encodeIfPresent(id, forKey: .id)
try container.encodeIfPresent(type, forKey: .type)
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Sources/MapboxMaps/Style/Generated/Sources/RasterSource.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Sources/MapboxMaps/Style/Generated/Sources/VectorSource.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Sources/MapboxMaps/Style/StyleSourceManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,15 @@ internal final class StyleSourceManager: StyleSourceManagerProtocol {
try handleExpected {
styleManager.addStyleCustomRasterSource(forSourceId: source.id, options: options)
}
try setVolatileProperties(source)
case let source as CustomGeometrySource:
guard let options = source.options else {
throw StyleError(message: "CustomGeometrySource does not have CustomGeometrySourceOptions")
}
try handleExpected {
styleManager.addStyleCustomGeometrySource(forSourceId: source.id, options: options)
}
try setVolatileProperties(source)
case let source as GeoJSONSource:
try addGeoJSONSource(source, dataId: dataId)
default:
Expand All @@ -94,10 +96,12 @@ internal final class StyleSourceManager: StyleSourceManagerProtocol {
private func addSourceInternal(_ source: Source) throws {
let sourceDictionary = try source.jsonObject(userInfo: [.nonVolatilePropertiesOnly: true])
try addSource(withId: source.id, properties: sourceDictionary)
try setVolatileProperties(source)
}

private func setVolatileProperties(_ source: Source) throws {
// volatile properties have to be set after the source has been added to the style
let volatileProperties = try source.jsonObject(userInfo: [.volatilePropertiesOnly: true])

try setSourceProperties(for: source.id, properties: volatileProperties)
}

Expand Down
Loading

0 comments on commit 942afd6

Please sign in to comment.