mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 10:59:39 +00:00 
			
		
		
		
	Merge pull request #3 from GayPizzaSpecifications/parallel-regen
Parallelize chunk generation using fan-out pattern.
This commit is contained in:
		@ -7,6 +7,9 @@ add_executable(Voxelotl MACOSX_BUNDLE
 | 
				
			|||||||
  shadertypes.h
 | 
					  shadertypes.h
 | 
				
			||||||
  shader.metal
 | 
					  shader.metal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Common library
 | 
				
			||||||
 | 
					  Common/ConcurrentDictionary.swift
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Maths library
 | 
					  # Maths library
 | 
				
			||||||
  Math/FloatExtensions.swift
 | 
					  Math/FloatExtensions.swift
 | 
				
			||||||
  Math/IntegerExtensions.swift
 | 
					  Math/IntegerExtensions.swift
 | 
				
			||||||
@ -98,6 +101,7 @@ set_source_files_properties(test.png PROPERTIES MACOSX_PACKAGE_LOCATION Resource
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#TODO: should use TREE mode as documented in https://cmake.org/cmake/help/latest/command/source_group.html
 | 
					#TODO: should use TREE mode as documented in https://cmake.org/cmake/help/latest/command/source_group.html
 | 
				
			||||||
source_group("Resources" FILES Assets.xcassets test.png)
 | 
					source_group("Resources" FILES Assets.xcassets test.png)
 | 
				
			||||||
 | 
					source_group("Source Files\\Common" REGULAR_EXPRESSION "Common/")
 | 
				
			||||||
source_group("Source Files" REGULAR_EXPRESSION "\\.(swift|metal)$")
 | 
					source_group("Source Files" REGULAR_EXPRESSION "\\.(swift|metal)$")
 | 
				
			||||||
source_group("Source Files\\Random" REGULAR_EXPRESSION "Random/")
 | 
					source_group("Source Files\\Random" REGULAR_EXPRESSION "Random/")
 | 
				
			||||||
source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
 | 
					source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										73
									
								
								Sources/Voxelotl/Common/ConcurrentDictionary.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								Sources/Voxelotl/Common/ConcurrentDictionary.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ConcurrentDictionary<V: Hashable, T>: Collection {
 | 
				
			||||||
 | 
					  private var inner: [V : T]
 | 
				
			||||||
 | 
					  private var lock: NSLock = .init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public var keys: Dictionary<V, T>.Keys {
 | 
				
			||||||
 | 
					    self.locked {
 | 
				
			||||||
 | 
					      inner.keys
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public var values: Dictionary<V, T>.Values {
 | 
				
			||||||
 | 
					      self.locked {
 | 
				
			||||||
 | 
					        self.inner.values
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public var startIndex: Dictionary<V, T>.Index {
 | 
				
			||||||
 | 
					      self.locked {
 | 
				
			||||||
 | 
					          self.inner.startIndex
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public var endIndex: Dictionary<V, T>.Index {
 | 
				
			||||||
 | 
					      self.locked {
 | 
				
			||||||
 | 
					          self.inner.endIndex
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public init(inner: [V:T]) {
 | 
				
			||||||
 | 
					    self.inner = inner
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public convenience init() {
 | 
				
			||||||
 | 
					    self.init(inner: [:])
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public func index(after i: Dictionary<V, T>.Index) -> Dictionary<V, T>.Index {
 | 
				
			||||||
 | 
					    self.locked {
 | 
				
			||||||
 | 
					      self.inner.index(after: i)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public subscript(key: V) -> T? {
 | 
				
			||||||
 | 
					      set(newValue) {
 | 
				
			||||||
 | 
					          self.locked {
 | 
				
			||||||
 | 
					            self.inner[key] = newValue
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      get {
 | 
				
			||||||
 | 
					        self.locked {
 | 
				
			||||||
 | 
					          self.inner[key]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public subscript(index: Dictionary<V, T>.Index) -> Dictionary<V, T>.Element {
 | 
				
			||||||
 | 
					      self.locked {
 | 
				
			||||||
 | 
					        self.inner[index]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fileprivate func locked<X>(_ perform: () -> X) -> X {
 | 
				
			||||||
 | 
					    self.lock.lock()
 | 
				
			||||||
 | 
					    defer {
 | 
				
			||||||
 | 
					      self.lock.unlock()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let value = perform()
 | 
				
			||||||
 | 
					    return value
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -62,15 +62,26 @@ public class World {
 | 
				
			|||||||
  func generate(width: Int, height: Int, depth: Int, seed: UInt64) {
 | 
					  func generate(width: Int, height: Int, depth: Int, seed: UInt64) {
 | 
				
			||||||
    self._generator.reset(seed: seed)
 | 
					    self._generator.reset(seed: seed)
 | 
				
			||||||
    let orig = SIMD3(width, height, depth) / 2
 | 
					    let orig = SIMD3(width, height, depth) / 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let localChunks = ConcurrentDictionary<ChunkID, Chunk>()
 | 
				
			||||||
 | 
					    let queue = OperationQueue()
 | 
				
			||||||
 | 
					    queue.qualityOfService = .userInitiated
 | 
				
			||||||
    for z in 0..<depth {
 | 
					    for z in 0..<depth {
 | 
				
			||||||
      for y in 0..<height {
 | 
					      for y in 0..<height {
 | 
				
			||||||
        for x in 0..<width {
 | 
					        for x in 0..<width {
 | 
				
			||||||
          let chunkID = SIMD3(x, y, z) &- orig
 | 
					          let chunkID = SIMD3(x, y, z) &- orig
 | 
				
			||||||
          self._chunks[chunkID] = self._generator.makeChunk(id: chunkID)
 | 
					          queue.addOperation {
 | 
				
			||||||
          self._chunkDamage.insert(chunkID)
 | 
					            let chunk = self._generator.makeChunk(id: chunkID)
 | 
				
			||||||
 | 
					            localChunks[chunkID] = chunk
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    queue.waitUntilAllOperationsAreFinished()
 | 
				
			||||||
 | 
					    for (chunkID, chunk) in localChunks {
 | 
				
			||||||
 | 
					      self._chunks[chunkID] = chunk
 | 
				
			||||||
 | 
					      self._chunkDamage.insert(chunkID)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  func generate(chunkID: ChunkID) {
 | 
					  func generate(chunkID: ChunkID) {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user