Skip to content

Commit

Permalink
Rework resource cache
Browse files Browse the repository at this point in the history
  • Loading branch information
STREGA committed Nov 28, 2023
1 parent 6ca60f5 commit ca4ab9b
Showing 12 changed files with 279 additions and 227 deletions.
43 changes: 25 additions & 18 deletions Sources/GateEngine/Resources/Animation/ObjectAnimation3D.swift
Original file line number Diff line number Diff line change
@@ -9,16 +9,11 @@
import Foundation
#endif

@MainActor public final class ObjectAnimation3D: Resource {
@MainActor public final class ObjectAnimation3D: Resource, _Resource {
internal let cacheKey: ResourceManager.Cache.ObjectAnimation3DKey

public var cacheHint: CacheHint {
get { Game.shared.resourceManager.objectAnimation3DCache(for: cacheKey)!.cacheHint }
set { Game.shared.resourceManager.changeCacheHint(newValue, for: cacheKey) }
}

public var state: ResourceState {
return Game.shared.resourceManager.objectAnimation3DCache(for: cacheKey)!.state
var cache: any ResourceCache {
return Game.shared.resourceManager.objectAnimation3DCache(for: cacheKey)!
}

@usableFromInline
@@ -92,7 +87,9 @@ import Foundation
path: path,
options: options
)
self.cacheHint = .until(minutes: 5)
if cachHintIsDefault {
self.cacheHint = .until(minutes: 5)
}
resourceManager.incrementReference(self.cacheKey)
}

@@ -103,7 +100,9 @@ import Foundation
duration: duration,
animation: animation
)
self.cacheHint = .until(minutes: 5)
if cachHintIsDefault {
self.cacheHint = .until(minutes: 5)
}
resourceManager.incrementReference(self.cacheKey)
}

@@ -521,26 +520,37 @@ extension ResourceManager {

extension ResourceManager.Cache {
@usableFromInline
struct ObjectAnimation3DKey: Hashable {
struct ObjectAnimation3DKey: Hashable, CustomStringConvertible {
let requestedPath: String
let options: ObjectAnimation3DImporterOptions

@usableFromInline
var description: String {
var string = requestedPath.first == "$" ? "(Generated)" : requestedPath
if let name = options.subobjectName {
string += "named: \(name)"
}
return string
}
}

@usableFromInline
final class ObjectAnimation3DCache {
final class ObjectAnimation3DCache: ResourceCache {
@usableFromInline var objectAnimation3DBackend: ObjectAnimation3DBackend?
var lastLoaded: Date
var state: ResourceState
var referenceCount: UInt
var minutesDead: UInt
var cacheHint: CacheHint
var cacheHint: CacheHint?
var defaultCacheHint: CacheHint
init() {
self.objectAnimation3DBackend = nil
self.lastLoaded = Date()
self.state = .pending
self.referenceCount = 0
self.minutesDead = 0
self.cacheHint = .until(minutes: 5)
self.cacheHint = nil
self.defaultCacheHint = .until(minutes: 5)
}
}
}
@@ -607,10 +617,7 @@ extension ResourceManager {
if case .whileReferenced = cache.cacheHint {
if cache.referenceCount == 0 {
self.cache.objectAnimation3Ds.removeValue(forKey: key)
Log.debug(
"Removing cache (no longer referenced), ObjectAnimation3D:",
key.requestedPath.first == "$" ? "(Generated)" : key.requestedPath
)
Log.debug("Removing cache (no longer referenced), ObjectAnimation3D: \(key)")
}
}
}
43 changes: 23 additions & 20 deletions Sources/GateEngine/Resources/Geometry/Geometry.swift
Original file line number Diff line number Diff line change
@@ -72,24 +72,19 @@ public extension Geometry {
/// Geometry represents a mangaed vertex buffer object.
/// It's contents are stored within GPU accessible memory and this object represents a reference to that memory.
/// When this object deinitializes it's contents will also be removed from GPU memory.
@MainActor public class Geometry: Resource {
@MainActor public class Geometry: Resource, _Resource {
@usableFromInline
internal let cacheKey: ResourceManager.Cache.GeometryKey

var cache: any ResourceCache {
return Game.shared.resourceManager.geometryCache(for: cacheKey)!
}

@usableFromInline
internal var backend: (any GeometryBackend)? {
return Game.shared.resourceManager.geometryCache(for: cacheKey)?.geometryBackend
}

public var cacheHint: CacheHint {
get { Game.shared.resourceManager.geometryCache(for: cacheKey)!.cacheHint }
set { Game.shared.resourceManager.changeCacheHint(newValue, for: cacheKey) }
}

public var state: ResourceState {
return Game.shared.resourceManager.geometryCache(for: cacheKey)!.state
}

@inlinable @inline(__always) @_disfavoredOverload
public convenience init(as path: GeoemetryPath, options: GeometryImporterOptions = .none) {
self.init(path: path.value, options: options)
@@ -98,14 +93,14 @@ public extension Geometry {
public init(path: String, options: GeometryImporterOptions = .none) {
let resourceManager = Game.shared.resourceManager
self.cacheKey = resourceManager.geometryCacheKey(path: path, options: options)
self.cacheHint = .until(minutes: 5)
self.defaultCacheHint = .until(minutes: 5)
resourceManager.incrementReference(self.cacheKey)
}

internal init(optionalRawGeometry rawGeometry: RawGeometry?) {
let resourceManager = Game.shared.resourceManager
self.cacheKey = resourceManager.geometryCacheKey(rawGeometry: rawGeometry)
self.cacheHint = .whileReferenced
self.defaultCacheHint = .whileReferenced
resourceManager.incrementReference(self.cacheKey)
}

@@ -214,26 +209,37 @@ extension RawGeometry {

extension ResourceManager.Cache {
@usableFromInline
struct GeometryKey: Hashable, Sendable {
struct GeometryKey: Hashable, Sendable, CustomStringConvertible {
let requestedPath: String
let geometryOptions: GeometryImporterOptions

@usableFromInline
var description: String {
var string = requestedPath.first == "$" ? "(Generated)" : requestedPath
if let name = geometryOptions.subobjectName {
string += ", Named: \(name)"
}
return string
}
}

@usableFromInline
class GeometryCache {
final class GeometryCache: ResourceCache {
@usableFromInline var geometryBackend: (any GeometryBackend)?
var lastLoaded: Date
var state: ResourceState
var referenceCount: UInt
var minutesDead: UInt
var cacheHint: CacheHint
var cacheHint: CacheHint?
var defaultCacheHint: CacheHint
init() {
self.geometryBackend = nil
self.lastLoaded = Date()
self.state = .pending
self.referenceCount = 0
self.minutesDead = 0
self.cacheHint = .until(minutes: 5)
self.cacheHint = nil
self.defaultCacheHint = .until(minutes: 5)
}
}
}
@@ -319,10 +325,7 @@ extension ResourceManager {
if case .whileReferenced = cache.cacheHint {
if cache.referenceCount == 0 {
self.cache.geometries.removeValue(forKey: key)
Log.debug(
"Removing cache (no longer referenced), Geometry:",
key.requestedPath.first == "$" ? "(Generated)" : key.requestedPath
)
Log.debug("Removing cache (no longer referenced), Geometry: \(key)")
}
}
}
21 changes: 8 additions & 13 deletions Sources/GateEngine/Resources/Geometry/Lines.swift
Original file line number Diff line number Diff line change
@@ -8,24 +8,19 @@
/// Geometry represents a mangaed vertex buffer object.
/// It's contents are stored within GPU accessible memory and this object represents a reference to that memory.
/// When this object deinitializes it's contents will also be removed from GPU memory.
@MainActor public class Lines: Resource {
@MainActor public class Lines: Resource, _Resource {
@usableFromInline
let cacheKey: ResourceManager.Cache.GeometryKey
internal let cacheKey: ResourceManager.Cache.GeometryKey

var cache: any ResourceCache {
return Game.shared.resourceManager.geometryCache(for: cacheKey)!
}

@usableFromInline
internal var backend: (any GeometryBackend)? {
return Game.shared.resourceManager.geometryCache(for: cacheKey)?.geometryBackend
}

public var cacheHint: CacheHint {
get { Game.shared.resourceManager.geometryCache(for: cacheKey)!.cacheHint }
set { Game.shared.resourceManager.changeCacheHint(newValue, for: cacheKey) }
}

public var state: ResourceState {
return Game.shared.resourceManager.geometryCache(for: cacheKey)!.state
}

@inlinable @inline(__always) @_disfavoredOverload
public convenience init(as path: GeoemetryPath, options: GeometryImporterOptions = .none) {
self.init(path: path.value, options: options)
@@ -34,14 +29,14 @@
public init(path: String, options: GeometryImporterOptions = .none) {
let resourceManager = Game.shared.resourceManager
self.cacheKey = resourceManager.linesCacheKey(path: path, options: options)
self.cacheHint = .until(minutes: 5)
self.defaultCacheHint = .until(minutes: 5)
resourceManager.incrementReference(self.cacheKey)
}

internal init(optionalRawLines rawLines: RawLines?) {
let resourceManager = Game.shared.resourceManager
self.cacheKey = resourceManager.linesCacheKey(rawLines: rawLines)
self.cacheHint = .whileReferenced
self.defaultCacheHint = .whileReferenced
resourceManager.incrementReference(self.cacheKey)
}

19 changes: 7 additions & 12 deletions Sources/GateEngine/Resources/Geometry/Points.swift
Original file line number Diff line number Diff line change
@@ -8,24 +8,19 @@
/// Geometry represents a mangaed vertex buffer object.
/// It's contents are stored within GPU accessible memory and this object represents a reference to that memory.
/// When this object deinitializes it's contents will also be removed from GPU memory.
@MainActor public class Points: Resource {
@MainActor public class Points: Resource, _Resource {
@usableFromInline
internal let cacheKey: ResourceManager.Cache.GeometryKey

var cache: any ResourceCache {
return Game.shared.resourceManager.geometryCache(for: cacheKey)!
}

@usableFromInline
internal var backend: (any GeometryBackend)? {
return Game.shared.resourceManager.geometryCache(for: cacheKey)?.geometryBackend
}

public var cacheHint: CacheHint {
get { Game.shared.resourceManager.geometryCache(for: cacheKey)!.cacheHint }
set { Game.shared.resourceManager.changeCacheHint(newValue, for: cacheKey) }
}

public var state: ResourceState {
return Game.shared.resourceManager.geometryCache(for: cacheKey)!.state
}

@inlinable @inline(__always) @_disfavoredOverload
public convenience init(as path: GeoemetryPath, options: GeometryImporterOptions = .none) {
self.init(path: path.value, options: options)
@@ -34,14 +29,14 @@
public init(path: String, options: GeometryImporterOptions = .none) {
let resourceManager = Game.shared.resourceManager
self.cacheKey = resourceManager.pointsCacheKey(path: path, options: options)
self.cacheHint = .whileReferenced
self.defaultCacheHint = .until(minutes: 5)
resourceManager.incrementReference(self.cacheKey)
}

internal init(optionalRawPoints rawPoints: RawPoints?) {
let resourceManager = Game.shared.resourceManager
self.cacheKey = resourceManager.pointsCacheKey(rawPoints: rawPoints)
self.cacheHint = .whileReferenced
self.defaultCacheHint = .whileReferenced
resourceManager.incrementReference(self.cacheKey)
}

42 changes: 22 additions & 20 deletions Sources/GateEngine/Resources/Geometry/SkinnedGeometry.swift
Original file line number Diff line number Diff line change
@@ -16,10 +16,14 @@ internal protocol SkinnedGeometryBackend: AnyObject {
/// Geometry represents a managed vertex buffer object.
/// It's contents are stored within GPU accessible memory and this object represents a reference to that memory.
/// When this object deinitializes it's contents will also be removed from GPU memory.
@MainActor public class SkinnedGeometry: Resource {
@MainActor public class SkinnedGeometry: Resource, _Resource {
@usableFromInline
internal let cacheKey: ResourceManager.Cache.SkinnedGeometryKey

var cache: any ResourceCache {
return Game.shared.resourceManager.skinnedGeometryCache(for: cacheKey)!
}

@usableFromInline
internal var backend: (any GeometryBackend)? {
return Game.shared.resourceManager.skinnedGeometryCache(for: cacheKey)?.geometryBackend
@@ -30,15 +34,6 @@ internal protocol SkinnedGeometryBackend: AnyObject {
return Game.shared.resourceManager.skinnedGeometryCache(for: cacheKey)!.skinJoints!
}

public var cacheHint: CacheHint {
get { Game.shared.resourceManager.skinnedGeometryCache(for: cacheKey)!.cacheHint }
set { Game.shared.resourceManager.changeCacheHint(newValue, for: cacheKey) }
}

public var state: ResourceState {
return Game.shared.resourceManager.skinnedGeometryCache(for: cacheKey)!.state
}

@inlinable @inline(__always) @_disfavoredOverload
public convenience init(
as path: GeoemetryPath,
@@ -59,7 +54,7 @@ internal protocol SkinnedGeometryBackend: AnyObject {
geometryOptions: geometryOptions,
skinOptions: skinOptions
)
self.cacheHint = .until(minutes: 5)
self.defaultCacheHint = .until(minutes: 5)
resourceManager.incrementReference(self.cacheKey)
}

@@ -69,7 +64,7 @@ internal protocol SkinnedGeometryBackend: AnyObject {
rawGeometry: rawGeometry,
skin: skin
)
self.cacheHint = .whileReferenced
self.defaultCacheHint = .whileReferenced
resourceManager.incrementReference(self.cacheKey)
}

@@ -95,28 +90,38 @@ extension SkinnedGeometry: Equatable, Hashable {

extension ResourceManager.Cache {
@usableFromInline
struct SkinnedGeometryKey: Hashable, Sendable {
struct SkinnedGeometryKey: Hashable, Sendable, CustomStringConvertible {
let requestedPath: String
let geometryOptions: GeometryImporterOptions
let skinOptions: SkinImporterOptions

@usableFromInline
var description: String {
var string = requestedPath.first == "$" ? "(Generated)" : requestedPath
if let name = geometryOptions.subobjectName {
string += ", Named: \(name)"
}
return string
}
}

class SkinnedGeometryCache {
final class SkinnedGeometryCache: ResourceCache {
var geometryBackend: (any GeometryBackend)?
var skinJoints: [Skin.Joint]?
var lastLoaded: Date
var state: ResourceState
var referenceCount: UInt
var minutesDead: UInt
var cacheHint: CacheHint
var cacheHint: CacheHint?
var defaultCacheHint: CacheHint
init() {
self.geometryBackend = nil
self.skinJoints = nil
self.lastLoaded = Date()
self.state = .pending
self.referenceCount = 0
self.minutesDead = 0
self.cacheHint = .until(minutes: 5)
self.defaultCacheHint = .until(minutes: 5)
}
}
}
@@ -217,10 +222,7 @@ extension ResourceManager {
if case .whileReferenced = cache.cacheHint {
if cache.referenceCount == 0 {
self.cache.skinnedGeometries.removeValue(forKey: key)
Log.debug(
"Removing cache (no longer referenced), SkinnedGeometry:",
key.requestedPath.first == "$" ? "(Generated)" : key.requestedPath
)
Log.debug("Removing cache (no longer referenced), SkinnedGeometry: \(key)")
}
}
}
Loading

0 comments on commit ca4ab9b

Please sign in to comment.