Skip to content

Commit deeeec1

Browse files
authored
GPU Family Checks (#96)
1 parent 1bc3e25 commit deeeec1

File tree

2 files changed

+47
-36
lines changed

2 files changed

+47
-36
lines changed

Sources/VimKit/Geometry.swift

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
934946
extension 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

Sources/VimKit/Renderer/RenderPass+Shapes.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class RenderPassShapes: RenderPass {
5959
/// - renderEncoder: the render encoder to use
6060
private func encode(descriptor: DrawDescriptor, renderEncoder: MTLRenderCommandEncoder) {
6161

62-
guard let pipelineState, let normalsBuffer = geometry?.normalsBuffer else { return }
62+
guard let pipelineState else { return }
6363
renderEncoder.setRenderPipelineState(pipelineState)
6464
renderEncoder.setDepthStencilState(depthStencilState)
6565

0 commit comments

Comments
 (0)