Compute Function
kernel 식별자를 사용하기에 커널 함수라고도 불림
kernel 키워드를 사용해 시작하고, 리턴은 void 형이어야 함.
max_total_threads_per_threadgroup 함수속성을 사용해 쓰레드 그룹간의 최대 쓰레드수를 지정가능
단, MTLDevice 의 maxThreadsPerThreadgroup 값보다 크게되면 오류발생할수 있음.
[[max_total_threads_per_threadgroup(x)]]
kernel void my_kernel()
{
}
함수인자
디바이스, 상수버퍼 : [[buffer(index)]]
텍스처 : [[texture(index]]
샘플러 : [[sampler(index]]
쓰레드그룹 버퍼 : [[threadgroup(index]
두벡터를 더해 출력하는 커널함수
kernel void add_vectors(
const device float4 *inA[[buffer(0)]],
const device float4 *inB[[buffer(1)]],
device float4 *out[[buffer(2)]],
uint id[[thrad_position_in_grid]] )
{
out[id] = inA[id] + inB[id];
}
텍스처 출력도 가능
kernel void my_kernel (
texture2d<float, access::read> inT [[texture(0)]],
texture2d<float, access::write> outT [[texture(1)]],
uint id[[thread_position_in_grid]] )
{
float4 c = inT.read( id ).rgba;
outT.write( c.rgba, id );
}
버퍼의 인덱스를 지정하지 않는 경우 인자 순서대로 타입별 인덱스가 할당됨
kernel void my_kernel(
texture2d<half> src, // [[texture(0)]]
texture2d<half, access::write> dst, // [[texture(1)]]
sampler s, // [[sampler(0)]]
device myUserInfo *u // [[buffer(0)]]
)
ComputeFunction 예제
쉐이더코드
#include <metal_stdlib>
using namespace metal;
kernel void my_kernel (
texture2d<float, access::read> inT [[texture(0)]],
texture2d<float, access::write> outT [[texture(1)]],
uint id[[thread_position_in_grid]] )
{
float4 c = inT.read( id ).rgba;
outT.write( c.rgba, id );
}
swift 코드
파이프라인 구분
Vertex, Fragment : RenderPipeline
MTLRenderPipelineState
MTLRenderPipelineDescriptor
ComputeFunction : ComputePipeline
MTLComputePipelineState
MTLComputePipelineDescriptor
// 블로그에서 작성된 소스(단순 플로우 확인 용)
class MyClass {
var device: MTLDevice?
var library: MTLLibrary?
var commandQueue: MTLCommandQueue?
var computeFunction : MTLFunction?
var computePipeline : MTLComputePipelineState?
var inputTexture:MTLTexture?
var outputTexture:MTLTexture?
초기화를 진행한다.
func init() {
// 장치와 라이브러리
device = MTLCreateSystemDefaultDevice()
library = device.makeDefaultLibrary()
// 커널함수
computeFunction = library.makeFunction( name: "my_kernel")
computePipeline = device.makeComputePipelineState( function: computeFunction )
// 명령큐
commandQueue = device.makeCommandQueue()
}
입력 텍스처
func inputImage(_ image: UIImage) -> UIImage {
// 입력 텍스처
inputTexture = makeMTLTexture( image )
// 출력 텍스처
let textureDescriptor =
MTLTextureDescriptor.texture2DDescriptor(
pixelFormat: MTLPixelFormat.rgba8Unorm,
width:image.size.width,
height:image.size.height,
mipmapped:false
)
outTexture = self.device.makeTexture( descriptor: textureDescriptor)
// command encoder 생성
// MTLRenderCommandEncoder : vertex, fragment
// MTLComputeCommandEncoder : kernel
let buffer = commandQueue.makeCommandBuffer()
let encoder = buffer?.makeComputeCommandEncoder()
encoder.setComputePipelineState( computePipeline )
encoder.setTexture( inputTexture, index:0)
encoder.setTexture( outputTexture, index:1)
let threadGroupCount = MTLSizeMake(16, 16, 1)
encoder.dispatchThreadgroups(
MTLSizeMake(
Int(ceil(image.size.width / CGFloat(threadGroupCount.width ))),
Int(ceil(image.size.height / CGFloat(threadGroupCount.height ))),
1
), threadsPerThreadgroup: threadGroupCount )
encoder.endEncoding()
buffer.commit()
buffer.waitUntilCompleted()
return convert( from: outputTexture )
}
func makeMTLTexture( from image: UIImage )->MTLTexture {
let textureLoader = MTKTextureLoader( device: self.device )
let texture = textureLoader.newTexture( cgImage: image.cgImage, options: nil )
return texture;
}
func conver( from texture: MTLTexture) -> UIImage {
let w = texture.width
let h = texture.height
let bytesPerPixel:Int = 4
let imageByteCount = w * h * bytesPerPixel
let bytesPerRow = w * bytesPerPixel
var src = [UInt8](repeating: 0, count: Int(imageByteCount ))
let region = MTLRegionMake2D(0, 0, w, h)
texture.getBytes( &src, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0)
let bitmapInfo = CGBitmapInfo( rawValue:(CGBitmapInfo.byteOrder32Big.rawValue | CGImageAlphaInfo.premultipliedlast.rawValue))
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitsPerComponent = 8
let context = CGContext( data: &src,
width: w,
height: h,
bitsPerCompoenent: bitsPerCompoenent,
bytesPerRow: bytesPerRow,
space: colorSpace,
bitmapInfo: bitmapInfo.rawValue)
let cgImage = context?.makeImage()
let image = UIImage( cgImage: cgImage)
return image
}
}
'프로그래밍 > iOS,macOS' 카테고리의 다른 글
[iOS] CoreAudio AudioUnit (0) | 2019.10.08 |
---|---|
iOS 프레임워크 파이썬 스크립트 (0) | 2019.07.23 |
[iOS] GPUImage (0) | 2019.07.06 |
xcodebuild (0) | 2019.06.06 |
CocoaPods 라이브러리 배포 (0) | 2019.05.31 |
[Metal] MetalKit 플로우 분석 (0) | 2019.05.27 |
swift , iOS 기본 사항만 빠르게 살펴보기 (0) | 2019.05.23 |
swift - objective-c 혼합 사용 (0) | 2019.05.22 |
ios pods google 특이한 에러 (0) | 2017.01.26 |
cocoapods 관련 내용 (0) | 2017.01.10 |