2017-07-20 60 views
3

我試圖通過金屬使用默認MPSKernal過濾器通過蘋果和自定義compute Shaders應用實時相機過濾器。如何使用自定義計算着色器使用金屬並獲得非常流暢的性能?

在計算着色器,我做了就地編碼與MPSImageGaussianBlur 和代碼放在這裏

func encode(to commandBuffer: MTLCommandBuffer, sourceTexture: MTLTexture, destinationTexture: MTLTexture, cropRect: MTLRegion = MTLRegion.init(), offset : CGPoint) { 

    let blur = MPSImageGaussianBlur(device: device, sigma: 0) 
    blur.clipRect = cropRect 
    blur.offset = MPSOffset(x: Int(offset.x), y: Int(offset.y), z: 0) 

    let threadsPerThreadgroup = MTLSizeMake(4, 4, 1) 
    let threadgroupsPerGrid = MTLSizeMake(sourceTexture.width/threadsPerThreadgroup.width, sourceTexture.height/threadsPerThreadgroup.height, 1) 

    let commandEncoder = commandBuffer.makeComputeCommandEncoder() 
    commandEncoder.setComputePipelineState(pipelineState!) 
    commandEncoder.setTexture(sourceTexture, at: 0) 
    commandEncoder.setTexture(destinationTexture, at: 1) 

    commandEncoder.dispatchThreadgroups(threadgroupsPerGrid, threadsPerThreadgroup: threadsPerThreadgroup) 

    commandEncoder.endEncoding() 

    autoreleasepool { 
     var inPlaceTexture = destinationTexture 
     blur.encode(commandBuffer: commandBuffer, inPlaceTexture: &inPlaceTexture, fallbackCopyAllocator: nil) 
    } 
} 

但有時就地質地往往失敗,並最終在屏幕上創建一個挺舉效果

所以,如果任何人都可以建議我解決方案,而不使用就地紋理或如何使用fallbackCopyAllocator或使用compute shaders在一個真正有用的不同方式。

+0

你爲什麼在命令編碼器上調用'blur' _after_ call'endEncoding()'? –

+0

@MatthijsHollemans我使用命令編碼器將流水線狀態編碼爲GPU可理解的語言。這是通過創建** MTLLibrary **並創建一個函數,然後創建一個流水線狀態來編碼**命令編碼器**來完成的。命令編碼器的目的是設置進程的狀態(在這種情況下將計算着色器編碼到GPU)。完成編碼後,告訴GPU它已準備好將其編碼到GPU。謝謝。等待建議。 –

+0

我的不好,我誤解了你的代碼。 –

回答

1

我已經在這方面做了足夠的編碼(將計算着色器應用於攝像機的視頻流),並且遇到的最常見問題是「像素緩衝區重用」問題。

從樣本緩衝區創建的金屬紋理備份了由視頻會話管理的像素緩衝區,並且可以重新用於以下視頻幀,除非您保留對採樣緩衝區的引用(保留對金屬質感的參考是不夠的)。

請隨時看看我的代碼https://github.com/snakajima/vs-metal,它將各種計算着色器應用於實況視頻流。除了texture參數外,VSContext:set()方法還需要可選的sampleBuffer參數,並保留對sampleBuffer的引用,直到計算着色器的計算完成(在VSRuntime:encode()方法中)。

+0

這是足夠的信息來做我必須做的事情。感謝您的信息。一旦我在我的應用程序中進行集成和測試,我將對此進行更新。 –

相關問題