https://developer.apple.com/documentation/metal/setting_up_a_command_structure
"Discover how Metal executes commands on a GPU."
Metal이 GPU에서 명령을 실행하는 방법을 알아봅니다.
GPU가 대신 작업을 수행하도록 하려면 GPU에 명령을 보내야 합니다. 명령은 드로잉, 병렬 연산, 혹은 앱이 요구하는 리소스 관리를 수행합니다. Metal 앱과 GPU 사이의 관계는 클라이언트 서버 패턴입니다.
Figure 1 Client-server usage pattern when using Metal.
GPU에 명령을 보내려면 명령 인코더 객체를 사용해서 명령 버퍼에 명령을 추가해야 합니다. 명령 큐에 명령 버퍼를 보내고, 명령 버퍼의 명령 실행을 위해 Metal의 준비가 되었을 때 명령 버퍼를 커밋해야 합니다. 명령 버퍼에 명령을 위치시키는 순서, 인큐 및 커밋 명령 버퍼는 중요합니다. 왜냐하면 이는 Metal이 명령을 실행하려고 약속한 지각된 순서에 영향을 미치기 때문입니다.
아래 섹션은 작동하는 명령 구조의 설정에 대한 단계들을 설명하며, Metal과 상호작용하기 위해 객체를 생성하는 순서로 진행됩니다.
초기화 시점에 Metal 객체를 생성할 수 있으며, 보통 무기한으로 유지합니다. 이들은 명령 큐이자 파이프라인 객체입니다. 설정의 비용이 많이 들기 때문에 한 번만 생성할 수 있으며, 한 번 초기화되면 재사용하기에는 빠릅니다.
명령 큐를 만드려면 기기의 makeCommandQueue()
함수를 호출해야 합니다.
commandQueue = device.makeCommandQueue()
보통 명령 큐를 재사용하기 때문에 강한 참조로 만들어야 합니다. 아래에 보이는 것처럼 명령 버퍼를 갖고 있기 위해 명령 큐를 사용할 수 있습니다.
Figure 2 Your app's command queue.
파이프라인 객체는 Metal에게 명령을 어떻게 처리할지 알려줍니다. 파이프라인 객체는 Metal shading 언어에 작성한 함수를 캡슐화합니다. 아래는 Metal 작업흐름에 파이프라인이 맞춰지는 방법을 보여줍니다.
Metal은 드로잉, 연산, blit 호출을 즉시 수행하지 않습니다. 대신 명령 버퍼에 해당 호출을 캡슐화 하는 명령에 삽입하기 위해 인코더 객체를 사용할 수 있습니다. 명령 버퍼를 커밋한 후, Metal은 이를 GPU에 보내고 명령 처리를 위해 활성화된 파이프라인 객체를 사용합니다.
Figure 3 The active pipeline on the GPU containing your custom shader code that processes commands.
명령 큐 및 파이프라인 설정으로 GPU에 명령을 보낼 차례입니다. 따라야 하는 프로세스는 아래와 같습니다.
렌더링 루프의 부분으로써 애니메이션을 수행하는 중이라면, 애니메이션의 모든 프레임에 이와 같이 해야 합니다. 또한, 일회성 이미지 처리 혹은 머신러닝 작업 실행을 실행하기 위해 이 프로세스를 따라야 합니다.
아래 하위 섹션은 이러한 단계들을 자세히 살펴봅니다.
명령 큐에서 makeCommandBuffer()
를 호출해서 명령 버퍼를 생성합니다.
Listing 2 Creating a command buffer.
guard let commandBuffer = commandQueue.makeCommandBuffer() else {
return
}
싱글 스레드 앱의 경우 단일 명령 버퍼를 생성할 수 있습니다. Figure 4는 명령 및 명령 버퍼 사이의 관계를 보여줍니다.
Figure 4 A command buffer's relationship to the commands it contains.
인코더 객체에서 task-specific 함수(드로잉, 연산, 블릿 작업 같은)를 호출하는 경우 인코더는 명령 버퍼 속으로 해당 호출에 상응하는 명령을 위치시킵니다. 인코더는 GPU가 런타임에 작업을 처리하는 데 필요한 모든 것을 포함하기 위해 명령을 인코딩합니다. Figure 5는 작업흐름을 보여줍니다.
Figure 5 Command encoder inserting commands into a command buffer as the result of a draw.
작업에 따라 MTLCommandEncoder
의 구체화된 서브클래스로 실제 명령을 인코딩할 수 있습니다.
MTLRenderCommandEncoder
를 사용합니다.MTLComputeCommandEncoder
를 사용합니다.MTLBlitCommandEncoder
를 사용합니다.렌더링 예시는 Using a Render Pipeline to Render Primitive를 보시기 바랍니다. 병령 프로세싱 예시는 Processing a Texture in a Compute Function을 보시기 바랍니다.
Using a Render Pipeline to Render Primitive
https://developer.apple.com/documentation/metal/using_a_render_pipeline_to_render_primitives
Processing a Texture in a Compute Function
https://developer.apple.com/documentation/metal/processing_a_texture_in_a_compute_function
명령을 실행할 수 있도록 하려면, GPU에 명령 버퍼를 커밋합니다.
To enable your commands to run, you commit the command buffer to the GPU:
commandBuffer.commit()
명령 버퍼를 커밋하는 것은 명령을 즉시 실행하도록 하지는 않습니다. 대신 Metal은 큐에서 기다리고 있는 명령 버퍼를 우선 커밋한 후에만 실행을 위한 버퍼의 명령을 스케줄링합니다. 명시적으로 명령 버퍼를 큐에 넣지 않으면, Metal은 버퍼를 커밋할 때 수행합니다.
커밋된 이후 버퍼의 재사용은 하지 않아야 합니다. 하지만 스케줄링, 컴플리션, 쿼리 상태의 노티피케이션을 선택할 수 있습니다. Metal이 하고 있는 약속은 명령이 실행되는 인지된 순서와 순서를 정해둔 방법과 같다는 것입니다. Metal이 명령 프로세싱 전 명령의 몇 가지 순서를 조정할 수 있지만, 이는 성능 향상이 있거나 인지할 수 없는 영향이 있을 때에만 순서를 조정합니다.
나중의 GPU 사용을 일시정지하고 이전 작업이 스케줄링 되는 것을 확실히 함으로써 앱이 백그라운드에 이동할 준비를 합니다.
https://developer.apple.com/documentation/metal/preparing_your_metal_app_to_run_in_the_background
https://velog.io/@panther222128/Preparing-Your-Metal-App-to-Run-in-the-Background
앱에서 GPU 통계를 측정해 성능을 향상시킵니다.
https://developer.apple.com/documentation/metal/counter_sampling
https://velog.io/@panther222128/Counter-Sampling