[all] It works!
This commit is contained in:
		
							parent
							
								
									dfa603012f
								
							
						
					
					
						commit
						8dcd0910f1
					
				
					 4 changed files with 73 additions and 66 deletions
				
			
		| 
						 | 
				
			
			@ -86,11 +86,11 @@ class Renderer: NSObject, MTKViewDelegate {
 | 
			
		|||
            Vertex(position: Point(x:  1, y:  1), textureCoordinate: Point(x: 1, y: 1))
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        do {
 | 
			
		||||
            try field.updateBuffers()
 | 
			
		||||
        } catch let e {
 | 
			
		||||
            NSLog("Error updating buffers: \(e)")
 | 
			
		||||
        }
 | 
			
		||||
//        do {
 | 
			
		||||
//            try field.updateBuffers()
 | 
			
		||||
//        } catch let e {
 | 
			
		||||
//            NSLog("Error updating buffers: \(e)")
 | 
			
		||||
//        }
 | 
			
		||||
 | 
			
		||||
        let buffer = commandQueue.makeCommandBuffer()
 | 
			
		||||
        buffer.label = "Render"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,12 +24,8 @@ typedef struct {
 | 
			
		|||
    float2 textureCoordinate;
 | 
			
		||||
} RasterizerData;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int2 size;
 | 
			
		||||
    int numberOfBalls;
 | 
			
		||||
} Parameters;
 | 
			
		||||
 | 
			
		||||
typedef half3 Ball;
 | 
			
		||||
typedef int3 Parameters;
 | 
			
		||||
typedef float3 Ball;
 | 
			
		||||
 | 
			
		||||
vertex RasterizerData
 | 
			
		||||
passthroughVertexShader(uint vid                    [[vertex_id]],
 | 
			
		||||
| 
						 | 
				
			
			@ -42,20 +38,21 @@ passthroughVertexShader(uint vid                    [[vertex_id]],
 | 
			
		|||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float sampleAtPoint(float2, constant Ball*, uint);
 | 
			
		||||
float sampleAtPoint(float2, constant Ball*, int);
 | 
			
		||||
 | 
			
		||||
fragment float4
 | 
			
		||||
sampleToColorShader(RasterizerData in               [[stage_in]],
 | 
			
		||||
                    constant Parameters& parameters [[buffer(0)]],
 | 
			
		||||
                    constant Ball* balls            [[buffer(1)]])
 | 
			
		||||
{
 | 
			
		||||
    const float sample = sampleAtPoint(in.textureCoordinate, balls, parameters.numberOfBalls);
 | 
			
		||||
    const uint numberOfBalls = parameters.z;
 | 
			
		||||
    const float sample = sampleAtPoint(in.position.xy, balls, numberOfBalls);
 | 
			
		||||
 | 
			
		||||
    float4 out;
 | 
			
		||||
    if (sample > 1.0) {
 | 
			
		||||
        out = float4(0.0, 1.0, 0.0, 0.0);
 | 
			
		||||
        out = float4(0.0, 1.0, 0.0, 1.0);
 | 
			
		||||
    } else {
 | 
			
		||||
        out = float4(0.0, 0.0, 0.0, 0.0);
 | 
			
		||||
        out = float4(0.2, 0.2, 0.2, 1.0);
 | 
			
		||||
    }
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -63,11 +60,11 @@ sampleToColorShader(RasterizerData in               [[stage_in]],
 | 
			
		|||
float
 | 
			
		||||
sampleAtPoint(float2 point,
 | 
			
		||||
              constant Ball* balls,
 | 
			
		||||
              uint count)
 | 
			
		||||
              int count)
 | 
			
		||||
{
 | 
			
		||||
    float sample = 0.0;
 | 
			
		||||
    for (uint i = 0; i < count; i++) {
 | 
			
		||||
        constant Ball& ball = balls[i];
 | 
			
		||||
    for (int i = 0; i < count; i++) {
 | 
			
		||||
        Ball ball = balls[i];
 | 
			
		||||
        float r2 = ball.z * ball.z;     // Radius stored in z coordinate.
 | 
			
		||||
        float xDiff = point.x - ball.x;
 | 
			
		||||
        float yDiff = point.y - ball.y;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,12 @@ public struct Point {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extension Point: CustomStringConvertible {
 | 
			
		||||
    public var description: String {
 | 
			
		||||
        return "(\(x), \(y))"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public struct Vector {
 | 
			
		||||
    var dx: Float
 | 
			
		||||
    var dy: Float
 | 
			
		||||
| 
						 | 
				
			
			@ -39,3 +45,9 @@ public struct Vector {
 | 
			
		|||
        self.dy = dy
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extension Vector: CustomStringConvertible {
 | 
			
		||||
    public var description: String {
 | 
			
		||||
        return "(\(dx), \(dy))"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,17 +46,10 @@ public class Field {
 | 
			
		|||
                balls = balls.filter { bounds.contains($0.bounds) }
 | 
			
		||||
 | 
			
		||||
                // Update Metal state as needed.
 | 
			
		||||
//                updateThreadgroupSizes(withFieldSize: size)
 | 
			
		||||
//                parametersBuffer = nil
 | 
			
		||||
//                sampleTexture = nil
 | 
			
		||||
                populateParametersBuffer()
 | 
			
		||||
                if numberOfBallsBeforeFilter != balls.count {
 | 
			
		||||
                    ballBuffer = nil
 | 
			
		||||
                }
 | 
			
		||||
                do {
 | 
			
		||||
                    try updateBuffers()
 | 
			
		||||
                } catch let e {
 | 
			
		||||
                    NSLog("Error updating size: \(e)")
 | 
			
		||||
                    return
 | 
			
		||||
                    populateBallBuffer()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +98,10 @@ public class Field {
 | 
			
		|||
        let ball = Ball(radius: radius, position: position, velocity: Vector())
 | 
			
		||||
        balls.append(ball)
 | 
			
		||||
        NSLog("Added ball \(ball); fieldSize=\(size)")
 | 
			
		||||
 | 
			
		||||
        populateParametersBuffer()
 | 
			
		||||
        ballBuffer = nil
 | 
			
		||||
        populateBallBuffer()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MARK: - Metal Configuration
 | 
			
		||||
| 
						 | 
				
			
			@ -120,23 +117,55 @@ public class Field {
 | 
			
		|||
//    private var threadgroupSize = MTLSize(width: 16, height: 16, depth: 1)
 | 
			
		||||
 | 
			
		||||
    /// Create the Metal buffer containing basic parameters of the simulation.
 | 
			
		||||
    private func makeParametersBufferIfNeeded(withDevice device: MTLDevice) -> MTLBuffer? {
 | 
			
		||||
    private func populateParametersBuffer() {
 | 
			
		||||
        if parametersBuffer == nil {
 | 
			
		||||
            parametersBuffer = device.makeBuffer(length: MemoryLayout<Int>.stride * 3, options: [])
 | 
			
		||||
            guard let device = self.device else { return }
 | 
			
		||||
            let length = 16     // A Parameters struct in shader-land is an int3, which takes 16 bytes.
 | 
			
		||||
            parametersBuffer = device.makeBuffer(length: length, options: [])
 | 
			
		||||
            NSLog("Making parameters buffer, length:\(length)")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let parameters = parametersBuffer {
 | 
			
		||||
            var ptr = parameters.contents()
 | 
			
		||||
            var width = UInt32(size.width)
 | 
			
		||||
            parameters.addDebugMarker("Width", range: NSRange(location: parameters.contents().distance(to: ptr), length: 4))
 | 
			
		||||
            ptr = write(value: &width, to: ptr)
 | 
			
		||||
            var height = UInt32(size.height)
 | 
			
		||||
            parameters.addDebugMarker("Height", range: NSRange(location: parameters.contents().distance(to: ptr), length: 4))
 | 
			
		||||
            ptr = write(value: &height, to: ptr)
 | 
			
		||||
            var numberOfBalls = UInt32(self.balls.count)
 | 
			
		||||
            parameters.addDebugMarker("Number Of Balls", range: NSRange(location: parameters.contents().distance(to: ptr), length: 4))
 | 
			
		||||
            ptr = write(value: &numberOfBalls, to: ptr)
 | 
			
		||||
            NSLog("Populated parameters: w:\(width), h:\(height), n:\(numberOfBalls)")
 | 
			
		||||
        }
 | 
			
		||||
        return parametersBuffer
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Create a Metal buffer containing the current set of metaballs.
 | 
			
		||||
    /// @param device The Metal device to use to create the buffer.
 | 
			
		||||
    /// @return A new buffer containing metaball data.
 | 
			
		||||
    private func makeBallBufferIfNeeded(withDevice device: MTLDevice) -> MTLBuffer? {
 | 
			
		||||
    private func populateBallBuffer() {
 | 
			
		||||
        if ballBuffer == nil && balls.count > 0 {
 | 
			
		||||
            let sizeOfBall = MemoryLayout<Float>.stride * 3     // A Ball in shader-land is a float3.
 | 
			
		||||
            guard let device = self.device else { return }
 | 
			
		||||
            let sizeOfBall = 16     // A Ball in shader-land is a float3, which takes 16 bytes.
 | 
			
		||||
            let length = balls.count * sizeOfBall
 | 
			
		||||
            NSLog("Making ball buffer, length:\(length)")
 | 
			
		||||
            ballBuffer = device.makeBuffer(length: length, options: [])
 | 
			
		||||
        }
 | 
			
		||||
        return ballBuffer
 | 
			
		||||
 | 
			
		||||
        if let ballBuffer = ballBuffer {
 | 
			
		||||
            var ptr = ballBuffer.contents()
 | 
			
		||||
            var idx = 0
 | 
			
		||||
            for var ball in self.balls {
 | 
			
		||||
                ballBuffer.addDebugMarker("Ball \(idx)", range: NSRange(location: ballBuffer.contents().distance(to: ptr), length: 16))
 | 
			
		||||
                ptr = write(value: &ball.position.x, to: ptr)
 | 
			
		||||
                ptr = write(value: &ball.position.y, to: ptr)
 | 
			
		||||
                var r = ball.radius
 | 
			
		||||
                ptr = write(value: &r, to: ptr)
 | 
			
		||||
                ptr = ptr.advanced(by: 4)   // Skip 4 bytes to maintain alignment.
 | 
			
		||||
                NSLog("Populated ball: x:\(ball.position.x), y:\(ball.position.y), r:\(r)")
 | 
			
		||||
                idx += 1
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Create a Metal texture to hold sample values created by the sampling compute shader.
 | 
			
		||||
| 
						 | 
				
			
			@ -162,37 +191,6 @@ public class Field {
 | 
			
		|||
//        threadgroupCount = MTLSize(width: width + threadgroupSize.width - 1, height: height + threadgroupSize.height - 1, depth: 1)
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    /// Copy metaballs data into the parameters buffer.
 | 
			
		||||
    public func updateBuffers() throws {
 | 
			
		||||
        guard let device = self.device else {
 | 
			
		||||
            throw MetaballsError.metalError("Missing Metal device for update")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        guard let parameters = makeParametersBufferIfNeeded(withDevice: device),
 | 
			
		||||
              let balls = makeBallBufferIfNeeded(withDevice: device)
 | 
			
		||||
        else {
 | 
			
		||||
            throw MetaballsError.metalError("Couldn't create buffers")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var ptr = parameters.contents()
 | 
			
		||||
        
 | 
			
		||||
        var width = Int(size.width)
 | 
			
		||||
        ptr = write(value: &width, to: ptr)
 | 
			
		||||
        var height = Int(size.height)
 | 
			
		||||
        ptr = write(value: &height, to: ptr)
 | 
			
		||||
 | 
			
		||||
        var numberOfBalls = self.balls.count
 | 
			
		||||
        ptr = write(value: &numberOfBalls, to: ptr)
 | 
			
		||||
 | 
			
		||||
        ptr = balls.contents()
 | 
			
		||||
        for var ball in self.balls {
 | 
			
		||||
            ptr = write(value: &ball.position.x, to: ptr)
 | 
			
		||||
            ptr = write(value: &ball.position.y, to: ptr)
 | 
			
		||||
            var r = ball.radius
 | 
			
		||||
            ptr = write(value: &r, to: ptr)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func write<T>(value: inout T, to ptr: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer {
 | 
			
		||||
        let sizeOfType = MemoryLayout<T>.stride
 | 
			
		||||
        ptr.copyBytes(from: &value, count: sizeOfType)
 | 
			
		||||
| 
						 | 
				
			
			@ -206,8 +204,8 @@ public class Field {
 | 
			
		|||
        NSLog("Setting up Metal")
 | 
			
		||||
        self.device = device
 | 
			
		||||
//        sampleComputeState = try computePipelineStateForSamplingKernel(withDevice: device)
 | 
			
		||||
        parametersBuffer = makeParametersBufferIfNeeded(withDevice: device)
 | 
			
		||||
        ballBuffer = makeBallBufferIfNeeded(withDevice: device)
 | 
			
		||||
        populateParametersBuffer()
 | 
			
		||||
        populateBallBuffer()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//    public func computePipelineStateForSamplingKernel(withDevice device: MTLDevice) throws -> MTLComputePipelineState? {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue