@@ -41,6 +41,18 @@ public class Geometry: ObservableObject, @unchecked Sendable {
4141 @MainActor @Published
4242 public var state : State = . unknown
4343
44+ private var device : MTLDevice
45+
46+ /// Boolean flag indicating if indirect command buffers are supported or not.
47+ private var supportsIndirectCommandBuffers : Bool {
48+ device. supportsFamily ( . apple4)
49+ }
50+
51+ /// Boolean flag indicating if the device supports non-uniform threadgroup sizes.
52+ private var supportsNonUniformThreadGroupSizes : Bool {
53+ device. supportsFamily ( . apple4)
54+ }
55+
4456 /// Returns the combined positions (vertex) buffer of all of the vertices for all the meshes layed out in slices of [x,y,z]
4557 public private( set) var positionsBuffer : MTLBuffer ?
4658 /// Returns the combined index buffer of all of the indices.
@@ -80,6 +92,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
8092
8193 /// Initializer
8294 init ( _ bfast: BFast ) {
95+ self . device = MTLContext . device
8396 self . bfast = bfast
8497 for (index, buffer) in bfast. buffers. enumerated ( ) {
8598 // Skip the first buffer as it is only meta information
@@ -115,44 +128,40 @@ public class Geometry: ObservableObject, @unchecked Sendable {
115128
116129 publish ( state: . loading)
117130
118- let device = MTLContext . device
119- let supportsIndirectCommandBuffers = device. supportsFamily ( . apple4)
120- let cacheDir = FileManager . default. cacheDirectory
121-
122131 // 1) Build the positions (vertex) buffer
123- makePositionsBuffer ( device : device )
132+ makePositionsBuffer ( )
124133 incrementProgressCount ( )
125134
126135 // 2) Build the index buffer
127- makeIndexBuffer ( device : device )
136+ makeIndexBuffer ( )
128137 incrementProgressCount ( )
129138
130139 // 3) Build the normals buffer
131- await computeVertexNormals ( device : device , cacheDirectory : cacheDir )
140+ await computeVertexNormals ( )
132141 incrementProgressCount ( )
133142
134143 // 4) Build the materials buffer
135- await makeMaterialsBuffer ( device : device )
144+ await makeMaterialsBuffer ( )
136145 incrementProgressCount ( )
137146
138147 // 5) Build the submeshes buffer
139- await makeSubmeshesBuffer ( device : device )
148+ await makeSubmeshesBuffer ( )
140149 incrementProgressCount ( )
141150
142151 // 6) Build the meshes buffer
143- await makeMeshesBuffer ( device : device )
152+ await makeMeshesBuffer ( )
144153 incrementProgressCount ( )
145154
146155 // 7) Build the instances buffer
147- await makeInstancesBuffer ( device : device )
156+ await makeInstancesBuffer ( )
148157 incrementProgressCount ( )
149158
150159 // 8) Compute the bounding boxes
151- await computeBoundingBoxes ( device : device )
160+ await computeBoundingBoxes ( )
152161 incrementProgressCount ( )
153162
154163 // 9) Build the colors buffer
155- await makeColorsBuffer ( device : device )
164+ await makeColorsBuffer ( )
156165 incrementProgressCount ( )
157166
158167 // 10 Start indexing the file
@@ -185,7 +194,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
185194
186195 // MARK: Postions (Vertex Buffer Raw Data)
187196
188- private func makePositionsBuffer( device : MTLDevice ) {
197+ private func makePositionsBuffer( ) {
189198 let start = Date . now
190199 defer {
191200 let timeInterval = abs ( start. timeIntervalSinceNow)
@@ -207,7 +216,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
207216
208217 // MARK: Index Buffer
209218
210- private func makeIndexBuffer( device : MTLDevice ) {
219+ private func makeIndexBuffer( ) {
211220 let start = Date . now
212221 defer {
213222 let timeInterval = abs ( start. timeIntervalSinceNow)
@@ -317,9 +326,8 @@ public class Geometry: ObservableObject, @unchecked Sendable {
317326
318327 // MARK: Meshes
319328
320- /// Makes the meshes buffer
321- /// - Parameter device: the metal device to use.
322- private func makeMeshesBuffer( device: MTLDevice ) async {
329+ /// Makes the meshes buffer.
330+ private func makeMeshesBuffer( ) async {
323331 guard !Task. isCancelled else { return }
324332 let start = Date . now
325333 defer {
@@ -354,7 +362,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
354362
355363 // MARK: Submeshes
356364
357- private func makeSubmeshesBuffer( device : MTLDevice ) async {
365+ private func makeSubmeshesBuffer( ) async {
358366 guard !Task. isCancelled else { return }
359367
360368 let start = Date . now
@@ -426,9 +434,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
426434 private( set) var hiddeninstancedMeshes = Set < Int > ( )
427435
428436 /// Makes the instance buffer.
429- /// - Parameters:
430- /// - device: the metal device to use
431- private func makeInstancesBuffer( device: MTLDevice ) async {
437+ private func makeInstancesBuffer( ) async {
432438
433439 guard !Task. isCancelled else { return }
434440
@@ -575,8 +581,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
575581 // MARK: Materials
576582
577583 /// Makes the materials buffer.
578- /// - Parameter device: the metal device to use.
579- private func makeMaterialsBuffer( device: MTLDevice ) async {
584+ private func makeMaterialsBuffer( ) async {
580585 guard !Task. isCancelled else { return }
581586
582587 let start = Date . now
@@ -643,10 +648,7 @@ extension Geometry {
643648 }
644649
645650 /// Computes the vertiex normals on the GPU using Metal Performance Shaders.
646- /// - Parameters:
647- /// - device: the metal device to use
648- /// - cacheDirectory: the cache directory
649- private func computeVertexNormals( device: MTLDevice , cacheDirectory: URL ) async {
651+ private func computeVertexNormals( ) async {
650652
651653 let start = Date . now
652654 defer {
@@ -655,6 +657,7 @@ extension Geometry {
655657 }
656658
657659 // If the normals file has already been generated, just make the MTLBuffer from it
660+ let cacheDirectory = FileManager . default. cacheDirectory
658661 let normalsBufferFile = cacheDirectory. appending ( path: " \( sha256Hash) \( normalsBufferExtension) " )
659662 if FileManager . default. fileExists ( atPath: normalsBufferFile. path) {
660663 guard let normalsBuffer = device. makeBufferNoCopy ( normalsBufferFile, type: Float . self) else {
@@ -700,8 +703,13 @@ extension Geometry {
700703 let gridSize : MTLSize = . init( width: 1 , height: 1 , depth: 1 )
701704 let width = pipelineState. threadExecutionWidth
702705 let height = pipelineState. maxTotalThreadsPerThreadgroup / width
703- let threadgroupSize : MTLSize = . init( width: width, height: height, depth: 1 )
704- computeEncoder. dispatchThreadgroups ( gridSize, threadsPerThreadgroup: threadgroupSize)
706+ let threadsPerThreadgroup : MTLSize = . init( width: width, height: height, depth: 1 )
707+
708+ if supportsNonUniformThreadGroupSizes {
709+ computeEncoder. dispatchThreads ( gridSize, threadsPerThreadgroup: threadsPerThreadgroup)
710+ } else {
711+ computeEncoder. dispatchThreadgroups ( gridSize, threadsPerThreadgroup: threadsPerThreadgroup)
712+ }
705713
706714 computeEncoder. endEncoding ( )
707715 commandBuffer. commit ( )
@@ -717,8 +725,7 @@ extension Geometry {
717725 }
718726
719727 /// Computes all of the instance bounding boxes on the GPU via Metal Performance Shaders.
720- /// - Parameter device: the device to use
721- private func computeBoundingBoxes( device: MTLDevice ) async {
728+ private func computeBoundingBoxes( ) async {
722729 let start = Date . now
723730 defer {
724731 let timeInterval = abs ( start. timeIntervalSinceNow)
@@ -753,7 +760,12 @@ extension Geometry {
753760 let width = pipelineState. threadExecutionWidth
754761 let height = pipelineState. maxTotalThreadsPerThreadgroup / width
755762 let threadsPerThreadgroup : MTLSize = . init( width: width, height: height, depth: 1 )
756- computeEncoder. dispatchThreads ( gridSize, threadsPerThreadgroup: threadsPerThreadgroup)
763+
764+ if supportsNonUniformThreadGroupSizes {
765+ computeEncoder. dispatchThreads ( gridSize, threadsPerThreadgroup: threadsPerThreadgroup)
766+ } else {
767+ computeEncoder. dispatchThreadgroups ( gridSize, threadsPerThreadgroup: threadsPerThreadgroup)
768+ }
757769
758770 computeEncoder. endEncoding ( )
759771 commandBuffer. commit ( )
@@ -934,8 +946,7 @@ extension Geometry {
934946extension Geometry {
935947
936948 /// Makes the color overrides buffer
937- /// - Parameter device: the metal device to use
938- private func makeColorsBuffer( device: MTLDevice ) async {
949+ private func makeColorsBuffer( ) async {
939950 guard !Task. isCancelled else { return }
940951
941952 let start = Date . now
0 commit comments