在iOS上,Shadertoy着色器端口到金属缓慢

时间:2017-04-17 07:33:44

标签: ios macos 3d shader metal

我正在尝试学习金属着色器,所以我将Shadertoy发现的山一代着色器移植到Metal。

https://www.shadertoy.com/view/llsGW7

端口有效,但在iOS上速度很慢。它在OS X上相当快,但在增加窗口大小时会变慢。在OS X游乐场中也很慢。

我已经在MetalKit.org上完成了教程并阅读了有关金属着色语言的苹果文档,但感觉我在概念上缺乏一切如何在幕后工作。如果在这段代码中有任何跳出来的东西显然会减慢速度,我将非常感激学习。我不确定减速是由于着色器代码本身,还是它所有设置的方式。

这是金属着色器:

#include <metal_stdlib>
using namespace metal;

constexpr sampler textureSampler(coord::normalized,
                             address::repeat,
                             min_filter::linear,
                             mag_filter::linear,
                             mip_filter::linear );

kernel void compute(texture2d<float, access::write> output [[texture(0)]],
                texture2d<float, access::sample> input [[texture(1)]],
                constant float &timer [[buffer(0)]],
                uint2 gid [[thread_position_in_grid]])
{
int width = input.get_width();
int height = input.get_height();

float2 uv = float2(gid) / float2(width, height);

float4 p = float4(uv,1,1)-0.5;

p.y = -p.y;
float4 d = p*0.5;
float4 t;
float4 c;

p.z += timer*200;
d.y-=0.2;

for(float i=1.7;i>0.0;i-=0.002) {
    float s=0.5;

    t = input.sample(textureSampler,0.3+p.xz*s/3e3) / (s+=s);
    // this makes it purple
    c = float4(1.0,-0.9,0.8,9.0)+d.x-t*i;

    //        c = float4(1.0,0.9,0.8,9.0)+d.x-t*i;
    if (t.x > p.y*.01+1.3) {
        break;
    }
    p += d;
}
output.write(c, gid);
}

这里是MTKView的子类,用于渲染着色器

import Cocoa
import MetalKit

class MetalView: MTKView {

var queue: MTLCommandQueue!
var cps: MTLComputePipelineState!
var timer: Float = 0
var timerBuffer: MTLBuffer!
var shaderName: String!
var texture: MTLTexture!

required public init(coder: NSCoder) {
    super.init(coder: coder)
    self.framebufferOnly = false
    self.preferredFramesPerSecond = 60
    registerShaders()
    setupTexture()

}

func setupTexture() {
    let path = Bundle.main.path(forResource: "texture", ofType: "jpg")
    let textureLoader = MTKTextureLoader(device: device!)
    texture = try! textureLoader.newTexture(withContentsOf: URL(fileURLWithPath: path!), options: nil)
}

func registerShaders() {
    device = MTLCreateSystemDefaultDevice()!
    queue = device!.makeCommandQueue()
    do {
        let library = device!.newDefaultLibrary()!
        let kernel = library.makeFunction(name: "compute")!
        cps = try device!.makeComputePipelineState(function: kernel)
    } catch let e {
        Swift.print("\(e)")
    }
    timerBuffer = device!.makeBuffer(length: MemoryLayout<Float>.size, options: [])

}

override public func draw(_ dirtyRect: CGRect) {

    if let drawable = currentDrawable {
        let commandBuffer = queue.makeCommandBuffer()
        let commandEncoder = commandBuffer.makeComputeCommandEncoder()
        commandEncoder.setComputePipelineState(cps)
        commandEncoder.setTexture(drawable.texture, at: 0)
        commandEncoder.setTexture(texture, at: 1)
        commandEncoder.setBuffer(timerBuffer, offset: 0, at: 0)
        update()
        let threadGroupCount = MTLSizeMake(8, 8, 1)
        let threadGroups = MTLSizeMake(drawable.texture.width / threadGroupCount.width, drawable.texture.height / threadGroupCount.height, 1)
        commandEncoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount)
        commandEncoder.endEncoding()
        commandBuffer.present(drawable)
        commandBuffer.commit()
    }
}
func update() {
    timer += Float(1.0 / TimeInterval(self.preferredFramesPerSecond))
    let bufferPointer = timerBuffer.contents()
    memcpy(bufferPointer, &timer, MemoryLayout<Float>.size)

}

}

0 个答案:

没有答案
相关问题