git.iko.soy/metal-metaballs
on master help sign in
Added code to avoid rendering lag.
commit8961c852d008c566be5c2febd7221fbb87b723a7 authorvinivendra <vinivendra@gmail.com> dateWed 10 Feb 2016, 17:01 (11 years ago) parent175f901
1 file changed+35−11
PixelImage/MetalMetaballRenderer.swift+35−11
PixelImage/MetalMetaballRenderer.swift+35−11
@@ -9,6 +9,14 @@
99import Metal
1010import UIKit
1111
12+class TextureRef {
13+ var texture: MTLTexture
14+
15+ init(texture: MTLTexture) {
16+ self.texture = texture
17+ }
18+}
19+
1220class MetalMetaballRenderer: MetaballRenderer {
1321
1422 typealias TargetView = UIImageView
@@ -22,17 +30,19 @@ class MetalMetaballRenderer: MetaballRenderer {
2230 var previousSize = CGSize.zero
2331
2432 let context = MTLContext()
25− var renderingTexture: MTLTexture!
33+ var renderingTexture: TextureRef!
2634 var imageBuffer: UnsafeMutablePointer<Void>!
2735
2836 let dataSource: MetaballDataSource
2937
38+ var dirty = false
39+ var metalIsBusy = false
40+
3041 required init(dataSource: MetaballDataSource) {
3142 self.dataSource = dataSource
3243 }
3344
3445 func updateTargetView() {
35− let metaballs = dataSource.metaballs
3646
3747 // Re-alloc buffers if the size has changed
3848 if previousSize != targetView.size {
@@ -40,21 +50,36 @@ class MetalMetaballRenderer: MetaballRenderer {
4050 updateFrame()
4151 }
4252
53+ if metalIsBusy {
54+ dirty = true
55+ return
56+ } else {
57+ metalIsBusy = true
58+ dirty = false
59+ }
60+
4361 dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INTERACTIVE.rawValue), 0)) { () -> Void in
4462
4563 // Render graphics to metal texture
46− self.renderToRenderingTexture(metaballs: metaballs)
64+ self.renderToRenderingTexture()
65+ self.metalIsBusy = false
66+
4767 // Transform metal texture into image
48− let uiimage = self.image(texture: self.renderingTexture)
68+ let uiimage = self.image(texture: self.renderingTexture.texture)
4969
5070 dispatch_async(dispatch_get_main_queue(), { () -> Void in
5171 // Send image to view
5272 self.targetView.image = uiimage
73+
74+ // If the image is dirty, update it
75+ if self.dirty {
76+ self.updateTargetView()
77+ }
5378 })
5479 }
5580 }
5681
57− func renderToRenderingTexture(metaballs metaballs: [Metaball]) {
82+ func renderToRenderingTexture() {
5883 let width = Int(targetView.width)
5984 let height = Int(targetView.height)
6085
@@ -62,7 +87,7 @@ class MetalMetaballRenderer: MetaballRenderer {
6287 let textureDescriptor =
6388 MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
6489
65− renderingTexture = context.device.newTextureWithDescriptor(textureDescriptor)
90+ renderingTexture = TextureRef(texture: context.device.newTextureWithDescriptor(textureDescriptor))
6691 }
6792
6893 let kernelFunction: MTLFunction?
@@ -77,15 +102,13 @@ class MetalMetaballRenderer: MetaballRenderer {
77102 let threadGroups = MTLSizeMake(width / threadGroupCounts.width,
78103 height / threadGroupCounts.height, 1)
79104
80− // Create up-to-date metaball buffer
81− let metaballInfoBuffer = metaballBuffer(metaballs)
82−
83105 // Send commands to metal and render
84106 let commandBuffer = context.commandQueue.commandBuffer()
85107
86108 let commandEncoder = commandBuffer.computeCommandEncoder()
87109 commandEncoder.setComputePipelineState(pipeline)
88− commandEncoder.setTexture(renderingTexture, atIndex: 0)
110+ commandEncoder.setTexture(renderingTexture.texture, atIndex: 0)
111+ let metaballInfoBuffer = metaballBuffer()
89112 commandEncoder.setBuffer(metaballInfoBuffer, offset: 0, atIndex: 0)
90113 commandEncoder.dispatchThreadgroups(threadGroups,
91114 threadsPerThreadgroup: threadGroupCounts)
@@ -140,10 +163,11 @@ class MetalMetaballRenderer: MetaballRenderer {
140163 return image
141164 }
142165
143− func metaballBuffer(metaballs: [Metaball]) -> MTLBuffer {
166+ func metaballBuffer() -> MTLBuffer {
144167 // Create Float array for buffer
145168 // Exclude metaballs far from the view's bounds
146169 let border: CGFloat = 100
170+ let metaballs = self.dataSource.metaballs
147171 var floats: [Float] = metaballs.reduce([Float(0)]) { (var array, metaball) -> [Float] in
148172 let x = CGFloat(metaball.midX)
149173 let y = CGFloat(metaball.midY)