@@ -41,6 +41,18 @@ public class Geometry: ObservableObject, @unchecked Sendable {
41
41
@MainActor @Published
42
42
public var state : State = . unknown
43
43
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
+
44
56
/// Returns the combined positions (vertex) buffer of all of the vertices for all the meshes layed out in slices of [x,y,z]
45
57
public private( set) var positionsBuffer : MTLBuffer ?
46
58
/// Returns the combined index buffer of all of the indices.
@@ -80,6 +92,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
80
92
81
93
/// Initializer
82
94
init ( _ bfast: BFast ) {
95
+ self . device = MTLContext . device
83
96
self . bfast = bfast
84
97
for (index, buffer) in bfast. buffers. enumerated ( ) {
85
98
// Skip the first buffer as it is only meta information
@@ -115,44 +128,40 @@ public class Geometry: ObservableObject, @unchecked Sendable {
115
128
116
129
publish ( state: . loading)
117
130
118
- let device = MTLContext . device
119
- let supportsIndirectCommandBuffers = device. supportsFamily ( . apple4)
120
- let cacheDir = FileManager . default. cacheDirectory
121
-
122
131
// 1) Build the positions (vertex) buffer
123
- makePositionsBuffer ( device : device )
132
+ makePositionsBuffer ( )
124
133
incrementProgressCount ( )
125
134
126
135
// 2) Build the index buffer
127
- makeIndexBuffer ( device : device )
136
+ makeIndexBuffer ( )
128
137
incrementProgressCount ( )
129
138
130
139
// 3) Build the normals buffer
131
- await computeVertexNormals ( device : device , cacheDirectory : cacheDir )
140
+ await computeVertexNormals ( )
132
141
incrementProgressCount ( )
133
142
134
143
// 4) Build the materials buffer
135
- await makeMaterialsBuffer ( device : device )
144
+ await makeMaterialsBuffer ( )
136
145
incrementProgressCount ( )
137
146
138
147
// 5) Build the submeshes buffer
139
- await makeSubmeshesBuffer ( device : device )
148
+ await makeSubmeshesBuffer ( )
140
149
incrementProgressCount ( )
141
150
142
151
// 6) Build the meshes buffer
143
- await makeMeshesBuffer ( device : device )
152
+ await makeMeshesBuffer ( )
144
153
incrementProgressCount ( )
145
154
146
155
// 7) Build the instances buffer
147
- await makeInstancesBuffer ( device : device )
156
+ await makeInstancesBuffer ( )
148
157
incrementProgressCount ( )
149
158
150
159
// 8) Compute the bounding boxes
151
- await computeBoundingBoxes ( device : device )
160
+ await computeBoundingBoxes ( )
152
161
incrementProgressCount ( )
153
162
154
163
// 9) Build the colors buffer
155
- await makeColorsBuffer ( device : device )
164
+ await makeColorsBuffer ( )
156
165
incrementProgressCount ( )
157
166
158
167
// 10 Start indexing the file
@@ -185,7 +194,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
185
194
186
195
// MARK: Postions (Vertex Buffer Raw Data)
187
196
188
- private func makePositionsBuffer( device : MTLDevice ) {
197
+ private func makePositionsBuffer( ) {
189
198
let start = Date . now
190
199
defer {
191
200
let timeInterval = abs ( start. timeIntervalSinceNow)
@@ -207,7 +216,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
207
216
208
217
// MARK: Index Buffer
209
218
210
- private func makeIndexBuffer( device : MTLDevice ) {
219
+ private func makeIndexBuffer( ) {
211
220
let start = Date . now
212
221
defer {
213
222
let timeInterval = abs ( start. timeIntervalSinceNow)
@@ -317,9 +326,8 @@ public class Geometry: ObservableObject, @unchecked Sendable {
317
326
318
327
// MARK: Meshes
319
328
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 {
323
331
guard !Task. isCancelled else { return }
324
332
let start = Date . now
325
333
defer {
@@ -354,7 +362,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
354
362
355
363
// MARK: Submeshes
356
364
357
- private func makeSubmeshesBuffer( device : MTLDevice ) async {
365
+ private func makeSubmeshesBuffer( ) async {
358
366
guard !Task. isCancelled else { return }
359
367
360
368
let start = Date . now
@@ -426,9 +434,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
426
434
private( set) var hiddeninstancedMeshes = Set < Int > ( )
427
435
428
436
/// 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 {
432
438
433
439
guard !Task. isCancelled else { return }
434
440
@@ -575,8 +581,7 @@ public class Geometry: ObservableObject, @unchecked Sendable {
575
581
// MARK: Materials
576
582
577
583
/// Makes the materials buffer.
578
- /// - Parameter device: the metal device to use.
579
- private func makeMaterialsBuffer( device: MTLDevice ) async {
584
+ private func makeMaterialsBuffer( ) async {
580
585
guard !Task. isCancelled else { return }
581
586
582
587
let start = Date . now
@@ -643,10 +648,7 @@ extension Geometry {
643
648
}
644
649
645
650
/// 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 {
650
652
651
653
let start = Date . now
652
654
defer {
@@ -655,6 +657,7 @@ extension Geometry {
655
657
}
656
658
657
659
// If the normals file has already been generated, just make the MTLBuffer from it
660
+ let cacheDirectory = FileManager . default. cacheDirectory
658
661
let normalsBufferFile = cacheDirectory. appending ( path: " \( sha256Hash) \( normalsBufferExtension) " )
659
662
if FileManager . default. fileExists ( atPath: normalsBufferFile. path) {
660
663
guard let normalsBuffer = device. makeBufferNoCopy ( normalsBufferFile, type: Float . self) else {
@@ -700,8 +703,13 @@ extension Geometry {
700
703
let gridSize : MTLSize = . init( width: 1 , height: 1 , depth: 1 )
701
704
let width = pipelineState. threadExecutionWidth
702
705
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
+ }
705
713
706
714
computeEncoder. endEncoding ( )
707
715
commandBuffer. commit ( )
@@ -717,8 +725,7 @@ extension Geometry {
717
725
}
718
726
719
727
/// 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 {
722
729
let start = Date . now
723
730
defer {
724
731
let timeInterval = abs ( start. timeIntervalSinceNow)
@@ -753,7 +760,12 @@ extension Geometry {
753
760
let width = pipelineState. threadExecutionWidth
754
761
let height = pipelineState. maxTotalThreadsPerThreadgroup / width
755
762
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
+ }
757
769
758
770
computeEncoder. endEncoding ( )
759
771
commandBuffer. commit ( )
@@ -934,8 +946,7 @@ extension Geometry {
934
946
extension Geometry {
935
947
936
948
/// 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 {
939
950
guard !Task. isCancelled else { return }
940
951
941
952
let start = Date . now
0 commit comments