OpenGLES Programming Guide for iOS 번역 - 8장. 병렬처리와 OpenGL ES

OpenGL ES/iOS 2011. 9. 22. 11:29

본 번역은 얼마든지 정확하지 않을 수 있습니다. 참고용으로만 보시길... ^^;;;


병렬처리는 여러 일들이 동시에 발생하는 것을 나타냅니다. 병렬처리는 컴퓨터의 문맥에서는 일반적으로 여러 프로세서에서 동시에 작업을 수행하는 것을 말합니다. 작업을 동시에 실행하여 작업을 보다 빠르게 완료하고 사용자에서 본 애플 리케이션의 응답성이 향상됩니다. 확고한 디자인의 OpenGL ES 응용프로그램은 구체적인 형태의 병렬처리, 즉 CPU에서 응용프로그램의 처리와 GPU에서 OpenGL ES 처리 동시성을 볼 수 있습니다. "OpenGL ES 응용프로그램 디자인 지침 "에서 설명하는 기술의 대부분은 특히 CPU와 GPU사이의 뛰어난 병렬 처리를 실현하는 OpenGL 응용프로그램 작성을 목적으로하고 있습니다. 병렬 처리 애플 리케이션을 설계한다는 것은 응용프로그램이 실행하는 작업을 하위 작업으로 분해하고 동시에 안전하게 실행할 수있는 작업 순서대로 실행해야하는 작업을 식별하는 것을 의미합니다. 즉, 다른 작업에서 사용하는 리소스 또는 다른 작업로부터 반환된 결과 중 하나에 의존하는 작업을 계시하는 것을 의미합니다.

iOS의 각 프로세스는 한개 이상의 스레드로 구성되어 있습니다. 스레드는 프로세스의 코드를 실행하는 실행 흐름입니다. Apple은 기존 스레드와 Grand Central Dispatch( GCD )라는 기능을 모두 제공합니다. GCD 를 사용하여 응용프로그램 스레드 관리를 요구하지 않고도 응용프로그램을 소규모 작업에 분해 수 있습니다. GCD 는 장치에서 사용 가능한 코어 수를 기반으로 스레드를 할당 그 스레드에 대해 자동으로 작업 예약합니다.

높은 수준은 Cocoa Touch가 NSOperation과 NSOperationQueue을 제공하여 작업 단위의 생성 및 스케줄링을위한 Objective-C 추상화를 가능하게하고 있습니다.

이 장에서는 이러한 기술은 자세히 다루지 않습니다. OpenGL ES 응용프로그램에 병렬 처리를 추가하는 방법을 검토하기 전에 먼저 "Concurrency Programming Guide"를 참조 하십시오. 스레드를 수동으로 관리하는 경우, "Threading Programming Guide"도 참조 하십시오. 사용하는 기술에 관계없이 다중 스레드 시스템에서 OpenGL ES를 호출하면 추가 제한이 있습니다. 이 장에서는 다중 스레딩은 OpenGL ES 응용프로그램의 성능을 향상시킬 경우, OpenGL ES가 다중 스레드 응용프로그램 부과 제한, 그리고 OpenGL ES 응용프로그램에 병렬 처리를 구현하는 데 사용할 수있는 일반적인 설계 방법을 이해하는데 도움이 됩니다.

OpenGL 응용프로그램에 병렬 처리의 장점이 있는지 식별

멀티 스레드 응용프로그램을 만드려면 응용프로그램의 설계, 구현, 테스트에서 확실히 노력이 필요합니다. 스레드는 응용프로그램에 복잡성과 오버헤드를 추가하는 요소입니다. 응용프로그램은 작업자 스레드에 전달 수 있도록 데이터를 복사해야 하는 경우가 여러 스레드가 같은 리소스에 대한 액세스를 동기화해야 하는 경우가 있습니다. OpenGL ES 응용프로그램에 병렬 처리를 구현하려고하기 전에 "OpenGL ES 응용프로그램 디자인 지침"에서 설명하는 기법을 사용하여 먼저 단일 스레드 환경에서 OpenGL ES 코드를 최적화합니다. 처음에는 CPU와 GPU의 효율적인 병렬 처리의 달성에 집중하고 그 후에 병렬 프로그래밍 방식으로 성능의 이점을 제공할 수 있는지 여부에 대해 평가합니다.

병렬 처리에 적합한 후보는 다음 특성 중 하나 또는 모두 제공합니다.

● 응용프로그램이 OpenGL ES 렌더링에 의존하지 않는 많은 작업을 CPU에서 실행하는. 예를 들어, 게임은 게임의 세계를 시뮬레이션 컴퓨터에 조종되는 적의 인공 지능을 계산하여 사운드를 재생합니다. 이 시나리오에서는 많은 작업이 OpenGL ES 의 그리기 코드에 의존하지 않기 때문에 병렬 처리를 활용할 수 있습니다.

● 응용프로그램의 프로필을 조사한 결과, OpenGL ES의 렌더링 코드를 CPU에서 많은 시간을 보내고있는 것으로 나타났습니다. 이 시나리오에서는 응용프로그램이 GPU에 충분한 속도로 명령을 보낼 수 있지 않기 때문에, GPU는 유휴 상태입니다. CPU에 연결된 코드가 이미 최적화되어있는 경우는 동시에 실행되는 작업으로 작업을 분할함으로써 응용프로그램의 성능을 향상시킬 수 있습니다.

응용프로그램이 GPU를 대기하고 차단하는 경우, OpenGL ES의 드로잉과 병행하여 수행 가능한 작업이 없는 경우 응용프로그램은 병렬 처리에 적합한 후보가 없습니다. CPU와 GPU모두가 유휴 상태의 경우 OpenGL ES의 요구는 아마도 그 이상의 튜닝 필요가 없을 정도로 간단합니다.

OpenGL ES 는 각 컨텍스트를 단일 스레드로 제한

iOS의 스레드는 각각 단일 현재 OpenGL ES 렌더링 컨텍스트입니다. 응용프로그램이 OpenGL ES 함수를 호출할 때 OpenGL ES 는 현재 스레드에 연결된 컨텍스트를 암시적으로 참조하고 컨텍스트에 연결된 상태 또는 객체를 수정합니다.

OpenGL ES는 재진입 하지 않습니다. 여러 스레드에 연결된 동일한 컨텍스트를 동시에 수정하는 경우, 결과는 예측할 수 없습니다. 응용프로그램이 중단될 수도 있고, 렌더링이 정상적으로 되지 않을 수도 있습니다. 어떤 이유로 여러 스레드가 같은 컨텍스트를 대상으로하도록 설정하게되면, 그 컨텍스트에 대한 모든 OpenGL ES 호출에 뮤텍스를 배치하여 스레드를 동기화해야 합니다. 블록 상태가 OpenGL ES 명령( glFinish )는 스레드를 동기화하지 않습니다.

GCD 및 NSOperationQueue 객체는 선택한 스레드에서 작업을 실행할 수 있습니다. 이들은 해당 작업 전용 스레드를 만들 수도 있고 기존의 thread를 재이용하는 경우도 있습니다. 그러나 어느 경우에도 어떤 스레드가 작업을 실행할지 보장할 수 없습니다.
이것은 OpenGL ES 응용프로그램에 다음의 의미를 가집니다.

● 각 작업은 OpenGL ES 명령을 실행하기 전에 컨텍스트를 설정해야 한다.

● 응용프로그램은 동일한 컨텍스트에 액세스하는 두 가지 작업 동시 실행이 허용되지 않도록 해야한다.

● 각 작업은 종료하기 전에 컨텍스트를 삭제해야 한다.

OpenGL ES 응용프로그램에 병렬 처리를 구현하는 방법

병렬 처리가 가능한 OpenGL ES 응용프로그램은 OpenGL ES가 더 많은 작업을 GPU에 제공할 수 있도록 CPU의 병렬 처리에 집중한다. OpenGL 응용프로그램에 병렬 처리를 구현하는 경우 권장 사항을 보여줍니다.

● 응용프로그램을 동시에 실행할 수있는 OpenGL ES 작업과 OpenGL ES 이외의 작업 분해하는 OpenGL ES의 그리기 코드는 단일 작업으로 실행됩니다. 따라서 OpenGL ES의 그리기 코드는 단일 스레드에서 실행됩니다. 이 방법은 응용프로그램에 많은 CPU처리를 필요로하는 다른 작업이 있을 경우에 가장 유용합니다.

● 응용프로그램이 OpenGL ES 에 보낼 데이터를 준비에 많은 CPU시간을 보내는 경우는 렌더링 데이터를 준비하는 작업과 렌더링 명령을 OpenGL ES 로 전송하는 작업과 작업을 나눌 수 있습니다. 자세한 내용은 "OpenGL ES 는 각 컨텍스트를 단일 스레드로 제한"을 참조하십시오.

● 동시에 렌더링 가능한 여러 장면이있는 경우 이상의 컨텍스트에서 실행 가능한 작업이 있는 경우 응용프로그램은 여러 작업을 만들고 한개의 작업에  한개의 OpenGL ES 컨텍스트를 설정합니다. 복수의 컨텍스트가 같은 art assets에 액세스하려면 sharegroup를 사용하여 컨텍스트 사이에서 OpenGL ES 객체를 공유합니다. 자세한 내용은 "EAGL sharegroup는 컨텍스트의 OpenGL ES 객체를 관리"를 참조하십시오.

작업자 태스크의 OpenGL ES 연산 실행

일부 응용프로그램은 OpenGL ES에 데이터를 전달하기 전에 데이터에 대해 대량의 연산을 수행합니다. 예를 들어, 새로운 지오메트리를 만들거나 기존의 지오메트리를 애니메이션 하는 응용프로그램이 해당합니다. 가능한 경우 이러한 연산은 OpenGL ES 내부에서 실행합니다. 이것은 GPU 내부에서 사용할 수있는 뛰어난 병렬 처리를 활용하고 응용프로그램과 OpenGL ES 간의 결과의 복사에 따른 오버헤드를 줄일 수 있습니다.

그림 6-3의 방법은 OpenGL ES 객체를 업데이트하고 그들 객체를 사용하는 렌더링 명령을 번갈아 실행하는 것입니다. OpenGL ES 는 GPU에서 렌더링을 수행하고 동시에 CPU에서 응용프로그램 업데이트를 실행합니다. CPU에서 실행되는 연산이 GPU의 연산보다 처리 시간이 더 걸리면 그만큼 GPU 유휴 시간이 길어집니다. 이러한 상황에서 여러 CPU를 탑재하는 시스템의 병렬 처리를 사용할 수있는 경우가 있습니다. OpenGL ES 렌더링 코드를 다른 연산이나 처리 작업으로 분할하여 그들을 동시에 실행합니다. 그림 8-1은 역할 분담을 알기 쉽게 보여줍니다. 첫번째 작업은 두번째 작업을 사용하여 OpenGL 에 송신하는 데이터를 생성합니다.

그림 8-1. 별도의 스레드에 CPU 처리와 OpenGL ES

최고의 성능을 위해 응용프로그램에서 작업 간의 데이터 복사를 피할 필요가 있습니다. 하나의 작업에서 데이터를 계산하고 계산 결과를 다른 작업의 정점 버퍼 객체에 복사하는 대신 설치 코드 정점 버퍼 객체를 매핑하고 포인터를 직접 작업자 작업에 전달합니다.

응용프로그램에서 수정 작업을 하위로 더 분해할 수있는 경우 또한 이점을 얻을 수있는 가능성이 있습니다. 예를 들어, 두 개 이상의 정점 버퍼 객체가 있다고 가정하고 드로잉 명령을 전송하기 전에 각각의 객체를 업데이트해야 합니다. 각 객체는 다른 객체에 관계없이 계산을 다시 만들 수 있습니다. 이 시나리오에서는 각 버퍼에 대한 수정 연산이되어 NSOperationQueue 객체를 사용하여 작업을 관리합니다.

1. 현재 컨텍스트를 설정합니다.
2. 첫 번째 버퍼를 매핑합니다.
3. 그 버퍼를 채울 수 작업이 될 NSOperation 객체를 만듭니다.
4.. 연산을 연산 큐에 추가합니다.
5. 다른 버퍼에 대해 2 단계에서 4 단계를 수행합니다.
6. 연산 큐에 waitUntilAllOperationsAreFinished를 호출합니다.
7. 버퍼의 매핑을 해제합니다.
8. 렌더링 명령을 실행합니다.

여러 OpenGL ES 컨텍스트 사용

동시에 렌더링 가능한 여러 장면이 응용프로그램에있는 경우, 렌더링 필요한 장면마다 컨텍스트를 사용할 수 있습니다. 한개의 장면마다 한개의 컨텍스트를 만들고 각 컨텍스트를 한개의 연산 또는 작업에 할당합니다. 각 작업은 작업 자별 컨텍스트를 가지고 있기 때문에 어떤 작업도 렌더링 명령을 동시에 보낼 수 있습니다.

여러 컨텍스트를 사용하는 일반적인 방법은 각 컨텍스트가 서로 다른 스레드에서 실행되고 있는 상태에서, 다른 컨텍스트가 OpenGL ES 객체를 사용하는 동안 OpenGL ES 객체 업데이트는 한개의 컨텍스트를 가지게 하는것이다. 각 컨텍스트는 별도의 스레드에서 실행되므로 컨텍스트 작업이 다른 컨텍스트에 차단하는 것은 거이 없습니다. 이것을 구현하려면 응용프로그램에서 두개의 컨텍스트와 두개의 스레드를 만들고 각 스레드가 한개의 컨텍스트를 제어하도록 합니다. 또한 두 번째 스레드에서 응용프로그램이 업데이트하려고 하는 OpenGL ES 객체는 이중 버퍼에 저장하여야 합니다. 이것은 객체를 사용하는 측의 스레드가 다른 스레드가 OpenGL ES 객체를 수정하고있는 동안은 OpenGL ES 객체에 액세스할 수 없을 수 있기 때문입니다. 컨텍스트 사이의 변경 내용을 동기화하는 프로세스는 "EAGL sharegroup 는 컨텍스트의 OpenGL ES 객체를 관리"에 설명되어 있습니다.

OpenGL ES 응용프로그램의 스레드 가이드

OpenGL ES를 사용하는 응용프로그램에서 스레드를 성공하려면 다음 지침을 따르십시오.

● 한개의 컨텍스트에 대해 한개의 스레드만 사용합니다. 특정 컨텍스트를 위한 OpenGL ES 명령은 스레드로부터 안전하지 않습니다. 절대로 여러 스레드가 하나의 컨텍스트에 동시에 액세스하지 않도록 하십시오.

● GCD(Grand Central Dispatch)를 사용할 때는 전용 직렬 큐(Queue)를 사용하여 OpenGL ES 명령을 발송한다. 이 큐는 기존의 뮤텍스 패턴을 바꾸는 데 사용할 수 있습니다.

● 현재 컨텍스트를 추적한다. 스레드를 전환할 때, 아무것도 생각하지 않고 컨텍스트를 전환하는것은 간단하지만 이런 상황을 통해 그래픽 명령의 실행에 예기치 않은 영향을 미칩니다. 새로 만들어진 스레드로 전환하면 현재 컨텍스트를 설정하고 원래 스레드를 떠나기 전에 현재 컨텍스트를 삭제 해 두지 않으면 안됩니다.

: