Factor out per-frame stuff into a PerFrameObject<T> class; use it for the rendering Uniforms

This commit is contained in:
Eryn Wells 2018-11-22 08:29:14 -07:00
parent 65ffec18e9
commit 907a0845a7
2 changed files with 40 additions and 35 deletions

View file

@ -30,7 +30,6 @@ class Renderer: NSObject, MTKViewDelegate {
public let device: MTLDevice
let library: MTLLibrary
let commandQueue: MTLCommandQueue
var dynamicUniformBuffer: MTLBuffer
var pipelineState: MTLRenderPipelineState
var normalPipelineState: MTLRenderPipelineState
var depthState: MTLDepthStencilState
@ -38,9 +37,7 @@ class Renderer: NSObject, MTKViewDelegate {
let inFlightSemaphore = DispatchSemaphore(value: maxBuffersInFlight)
let regenerationSemaphore = DispatchSemaphore(value: 1)
var uniformBufferOffset = 0
var uniformBufferIndex = 0
var uniforms: UnsafeMutablePointer<Uniforms>
var uniforms: PerFrameObject<Uniforms>
var lightsBuffer: MTLBuffer
var lights: UnsafeMutablePointer<Light>
@ -71,14 +68,7 @@ class Renderer: NSObject, MTKViewDelegate {
self.device = metalKitView.device!
self.commandQueue = self.device.makeCommandQueue()!
let uniformBufferSize = alignedUniformsSize * maxBuffersInFlight
self.dynamicUniformBuffer = self.device.makeBuffer(length:uniformBufferSize,
options:[MTLResourceOptions.storageModeShared])!
self.dynamicUniformBuffer.label = "UniformBuffer"
uniforms = UnsafeMutableRawPointer(dynamicUniformBuffer.contents()).bindMemory(to:Uniforms.self, capacity:1)
uniforms = PerFrameObject(device: device, label: "Uniforms")
metalKitView.depthStencilPixelFormat = MTLPixelFormat.depth32Float_stencil8
metalKitView.colorPixelFormat = MTLPixelFormat.bgra8Unorm_srgb
@ -199,16 +189,6 @@ class Renderer: NSObject, MTKViewDelegate {
material[0].specularExponent = 10
}
private func updateDynamicBufferState() {
/// Update the state of our uniform buffers before rendering
uniformBufferIndex = (uniformBufferIndex + 1) % maxBuffersInFlight
uniformBufferOffset = alignedUniformsSize * uniformBufferIndex
uniforms = UnsafeMutableRawPointer(dynamicUniformBuffer.contents() + uniformBufferOffset).bindMemory(to:Uniforms.self, capacity:1)
}
private func updateGameState() {
/// Update any game state before rendering
if iterateTerrainAlgorithm {
@ -217,21 +197,21 @@ class Renderer: NSObject, MTKViewDelegate {
}
}
uniforms[0].projectionMatrix = projectionMatrix
uniforms.pointer[0].projectionMatrix = projectionMatrix
let rotationAxis = float3(0, 1, 0)
let modelMatrix = matrix4x4_rotation(radians: rotation, axis: rotationAxis)
let viewMatrix = matrix4x4_translation(0.0, -2.0, -8.0)
let modelViewMatrix = simd_mul(viewMatrix, modelMatrix)
uniforms[0].modelViewMatrix = modelViewMatrix
uniforms.pointer[0].modelViewMatrix = modelViewMatrix
rotation += 0.003
// Remove the fourth row and column from our model-view matrix. Since we're only doing rotations and translations (no scales), this serves as our normal transform matrix.
let rotSclModelViewMatrix = float3x3(modelViewMatrix.columns.0.xyz, modelViewMatrix.columns.1.xyz, modelViewMatrix.columns.2.xyz)
uniforms[0].normalMatrix = rotSclModelViewMatrix
uniforms.pointer[0].normalMatrix = rotSclModelViewMatrix
uniforms[0].terrainDimensions = terrain.dimensions
uniforms[0].terrainSegments = terrain.segments
uniforms.pointer[0].terrainDimensions = terrain.dimensions
uniforms.pointer[0].terrainSegments = terrain.segments
}
func draw(in view: MTKView) {
@ -256,7 +236,7 @@ class Renderer: NSObject, MTKViewDelegate {
inFlightSem.signal()
}
self.updateDynamicBufferState()
uniforms.updateOffsets()
self.updateGameState()
@ -270,7 +250,7 @@ class Renderer: NSObject, MTKViewDelegate {
didScheduleAlgorithmIteration = true
}
terrain.scheduleGeometryUpdates(inCommandBuffer: commandBuffer, uniforms: dynamicUniformBuffer, uniformsOffset: uniformBufferOffset)
terrain.scheduleGeometryUpdates(inCommandBuffer: commandBuffer, uniforms: uniforms)
/// Delay getting the currentRenderPassDescriptor until we absolutely need it to avoid
/// holding onto the drawable and blocking the display pipeline any longer than necessary
@ -293,8 +273,8 @@ class Renderer: NSObject, MTKViewDelegate {
renderEncoder.setTriangleFillMode(drawLines ? .lines : .fill)
renderEncoder.setVertexBuffer(terrain.faceNormalsBuffer, offset: 0, index: BufferIndex.faceNormals.rawValue)
renderEncoder.setVertexBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
renderEncoder.setFragmentBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: BufferIndex.uniforms.rawValue)
renderEncoder.setVertexBuffer(uniforms.buffer, offset: uniforms.offset, index: BufferIndex.uniforms.rawValue)
renderEncoder.setFragmentBuffer(uniforms.buffer, offset: uniforms.offset, index: BufferIndex.uniforms.rawValue)
renderEncoder.setFragmentBuffer(lightsBuffer, offset: 0, index: BufferIndex.lights.rawValue)
renderEncoder.setFragmentBuffer(materialBuffer, offset: 0, index: BufferIndex.materials.rawValue)
@ -366,7 +346,7 @@ class Renderer: NSObject, MTKViewDelegate {
encoder.setVertexBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: NormalBufferIndex.points.rawValue)
encoder.setVertexBuffer(normalBuffer.buffer, offset: normalBuffer.offset, index: NormalBufferIndex.normals.rawValue)
encoder.setVertexBuffer(dynamicUniformBuffer, offset: uniformBufferOffset, index: NormalBufferIndex.uniforms.rawValue)
encoder.setVertexBuffer(uniforms.buffer, offset: uniforms.offset, index: NormalBufferIndex.uniforms.rawValue)
encoder.drawPrimitives(type: .line, vertexStart: 0, vertexCount: 2, instanceCount: terrain.mesh.vertexCount)
encoder.popDebugGroup()
@ -381,9 +361,34 @@ class Renderer: NSObject, MTKViewDelegate {
encoder.setVertexBuffer(faceMidpointsBuffer, offset: 0, index: NormalBufferIndex.points.rawValue)
encoder.setVertexBuffer(faceNormalsBuffer, offset: 0, index: NormalBufferIndex.normals.rawValue)
encoder.setVertexBuffer(dynamicUniformBuffer, offset:uniformBufferOffset, index: NormalBufferIndex.uniforms.rawValue)
encoder.setVertexBuffer(uniforms.buffer, offset: uniforms.offset, index: NormalBufferIndex.uniforms.rawValue)
encoder.drawPrimitives(type: .line, vertexStart: 0, vertexCount: 2, instanceCount: instanceCount)
encoder.popDebugGroup()
}
}
struct PerFrameObject<T> {
static var objectSize: Int {
return (MemoryLayout<T>.size & ~0xFF) + 0x100
}
private(set) var offset: Int = 0
private(set) var index: Int = 0
private(set) var buffer: MTLBuffer
private(set) var pointer: UnsafeMutablePointer<T>
init(device: MTLDevice, label: String? = nil) {
let bufferSize = PerFrameObject<T>.objectSize * maxBuffersInFlight
buffer = device.makeBuffer(length: bufferSize, options: .storageModeShared)!
buffer.label = label
pointer = UnsafeMutableRawPointer(buffer.contents()).bindMemory(to: T.self, capacity: 1)
}
mutating func updateOffsets() {
index = (index + 1) % maxBuffersInFlight
offset = PerFrameObject<T>.objectSize * index
pointer = UnsafeMutableRawPointer(buffer.contents() + offset).bindMemory(to: T.self, capacity: 1)
}
}

View file

@ -154,7 +154,7 @@ class Terrain: NSObject {
return progress
}
func scheduleGeometryUpdates(inCommandBuffer commandBuffer: MTLCommandBuffer, uniforms: MTLBuffer, uniformsOffset: Int) {
func scheduleGeometryUpdates(inCommandBuffer commandBuffer: MTLCommandBuffer, uniforms: PerFrameObject<Uniforms>) {
if let computeEncoder = commandBuffer.makeComputeCommandEncoder() {
//print("Scheduling update geometry heights")
computeEncoder.label = "Geometry Heights Encoder"
@ -165,7 +165,7 @@ class Terrain: NSObject {
computeEncoder.setBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: GeneratorBufferIndex.meshPositions.rawValue)
let texCoordBuffer = mesh.vertexBuffers[BufferIndex.meshGenerics.rawValue]
computeEncoder.setBuffer(texCoordBuffer.buffer, offset: texCoordBuffer.offset, index: GeneratorBufferIndex.texCoords.rawValue)
computeEncoder.setBuffer(uniforms, offset: uniformsOffset, index: GeneratorBufferIndex.uniforms.rawValue)
computeEncoder.setBuffer(uniforms.buffer, offset: uniforms.offset, index: GeneratorBufferIndex.uniforms.rawValue)
computeEncoder.dispatchThreads(MTLSize(width: Int(segments.x + 1), height: Int(segments.y + 1), depth: 1), threadsPerThreadgroup: MTLSize(width: 8, height: 8, depth: 1))
computeEncoder.popDebugGroup()
computeEncoder.endEncoding()