@@ -21,9 +21,11 @@ class MetalMetaballRenderer: MetaballRenderer {
21 typealias TargetView = UIImageView
21 typealias TargetView = UIImageView
23 let targetView = TargetView()
23 let targetView = TargetView()
24+ var previousFrame = CGRect.zero
25 let context = MTLContext()
26 let context = MTLContext()
26− var internalTexture: MTLTexture!
27+ var renderingTexture: MTLTexture!
28+ var imageBuffer: UnsafeMutablePointer<Void>!
28 let dataSource: MetaballDataSource
30 let dataSource: MetaballDataSource
@@ -34,14 +36,19 @@ class MetalMetaballRenderer: MetaballRenderer {
34 func updateTargetView() {
36 func updateTargetView() {
35 let metaballs = dataSource.metaballs
37 let metaballs = dataSource.metaballs
39+ if previousFrame != targetView.frame {
40+ previousFrame = targetView.frame
37 let width = Int(targetView.width)
44 let width = Int(targetView.width)
38 let height = Int(targetView.height)
45 let height = Int(targetView.height)
40− if internalTexture == nil {
47+ if renderingTexture == nil {
41 let textureDescriptor =
48 let textureDescriptor =
42 MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
49 MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
44− internalTexture = context.device.newTextureWithDescriptor(textureDescriptor)
51+ renderingTexture = context.device.newTextureWithDescriptor(textureDescriptor)
47 let kernelFunction: MTLFunction?
54 let kernelFunction: MTLFunction?
@@ -64,7 +71,7 @@ class MetalMetaballRenderer: MetaballRenderer {
65 let commandEncoder = commandBuffer.computeCommandEncoder()
72 let commandEncoder = commandBuffer.computeCommandEncoder()
66 commandEncoder.setComputePipelineState(pipeline)
73 commandEncoder.setComputePipelineState(pipeline)
67− commandEncoder.setTexture(internalTexture, atIndex: 0)
74+ commandEncoder.setTexture(renderingTexture, atIndex: 0)
68 commandEncoder.setTexture(metaballInfoTexture, atIndex: 1)
75 commandEncoder.setTexture(metaballInfoTexture, atIndex: 1)
69 commandEncoder.dispatchThreadgroups(threadGroups,
76 commandEncoder.dispatchThreadgroups(threadGroups,
70 threadsPerThreadgroup: threadGroupCounts)
77 threadsPerThreadgroup: threadGroupCounts)
@@ -77,28 +84,27 @@ class MetalMetaballRenderer: MetaballRenderer {
77 print("Error!")
84 print("Error!")
80− targetView.image = image(texture: internalTexture)
87+ targetView.image = image(texture: renderingTexture)
83 func image(texture texture: MTLTexture) -> UIImage {
90 func image(texture texture: MTLTexture) -> UIImage {
84 let imageSize = CGSizeMake(CGFloat(texture.width),
91 let imageSize = CGSizeMake(CGFloat(texture.width),
85 CGFloat(texture.height))
92 CGFloat(texture.height))
87 let width = Int(imageSize.width)
93 let width = Int(imageSize.width)
88 let height = Int(imageSize.height)
94 let height = Int(imageSize.height)
90 let imageByteCount = width * height * 4
95 let imageByteCount = width * height * 4
97+ if imageBuffer == nil {
91− let imageBytes = malloc(imageByteCount)
98+ imageBuffer = malloc(imageByteCount)
92 let bytesPerRow = width * 4
101 let bytesPerRow = width * 4
93 let region = MTLRegionMake2D(0, 0, width, height)
102 let region = MTLRegionMake2D(0, 0, width, height)
94− texture.getBytes(imageBytes, bytesPerRow: bytesPerRow,
103+ texture.getBytes(imageBuffer, bytesPerRow: bytesPerRow,
95 fromRegion: region, mipmapLevel: 0)
104 fromRegion: region, mipmapLevel: 0)
97− let provider = CGDataProviderCreateWithData(nil, imageBytes,
106+ let provider = CGDataProviderCreateWithData(nil, imageBuffer,
98− imageByteCount) {
107+ imageByteCount, nil)
99− (_, data, _) -> Void in
100− free(UnsafeMutablePointer<Void>(data))
103 let bitsPerComponent = 8
109 let bitsPerComponent = 8
104 let bitsperPixel = 32
110 let bitsperPixel = 32
@@ -138,6 +144,17 @@ class MetalMetaballRenderer: MetaballRenderer {
139 return texture
145 return texture
148+ func updateFrame() {
149+ if imageBuffer != nil {