※ 이 글은 오가사와라 히로유키(小笠原博之) 씨가 블로그에 적은 글을 번역한 것입니다. 사정에 따라 예고없이 삭제될 수 있으므로 양해부탁드립니다.

(원문 :モバイルデバイスは Game Console を超えたかどうか)

모바일 기기는 게임 컨솔을 넘었을까

모바일 기기는 요 몇년간 상당한 속도로 향상되어 왔으며, 기세도 줄어들지 않고 있습니다. 지금까지 테스트해온 대로, GPU, CPU 모두 PC나 전용기기에 필적하는 능력을 갖게 되었습니다.

개성이 치우쳐진 모바일 프로세서

PC와 마찬가지로 단말의 성능에는 큰 격차가 있습니다.

현시점에서 입수할 수 있는 가장 빠른 CPU는 Snapdragon APQ8064 (Krait Quad core) 일 것입니다. 내일 2013/04/04은 1.7GHz의 옵티머스G Pro L-04E가 발매예정입니다.

지금 당장 구할 수 있는 단말의 GPU 로는 틀림없이 iPad4의 A6X가 가장 빠릅니다.

PowerVR SGX500~의 형번호를 가진 GPU는 여럿 존재하지만, 크게 나누어 2종류가 있습니다.

PowerVR Series 5        SGX530, SGX535, SGX540
PowerVR Series 5XT      SGX543MP, SGX544MP, SGX554MP

형번호가 비슷해서 헷갈리지만, 양쪽에는 PVRTC2, 섀도우 샘플러, 연산정밀도, 멀티코어 등 기능적인 차이가 있습니다. 그중에서도 최상위인 SGX554MP4 를 탑재하고 있는 것은 iPad4의 A6X뿐 입니다.

이와 같이 하이엔드 단말 중에서도 각자 무엇을 중시하는가에 따라 평가가 달라집니다. Apple은 GPU를 최우선하고 있는 반면, CPU가 쿼드코어인 단말은 아직 존재하지 않습니다.

방향성으로 정반대인 것이 NVIDIA Tegra입니다. 솔선해서 듀얼코어, 쿼드코어인 Tegra2/3를 전개해왔지만, 트레이드 오프로서 GPU 기능이 약하고, 묘화성능도 좋지 않습니다.

따라서, 성능차만이 아니라 성격에 있어서도 특성이 제각기였던 것이 지금까지의 모바일 기기의 특징이었습니다.

  • 트레이드 오프가 있으므로 일부분만 우수하다
  • 메이커 별로 강화하고 있는 분야가 다르다

하지만 다음 세대에서는 이러한 언밸런스함이 상당부분 해소될 것이라 생각됩니다.

세대교체

다른 회사에 앞서서 GPU/CPU 모두 세대교체를 달성한 Qualcomm에서는, 아주 특출난 점은 없지만 평균적인 전체 성능이 높아졌습니다.

또, 이후 등장 예정인 Tegra4는 CPU 코어가 쇄신될 뿐 아니라, 겨우 NVIDIA다운 GPU로 강화될 듯 합니다.

Tegra2/3의 GPU인 ULP GeForce는 셰이더 유닛이 discrete였기에 GeForce6800/7800 세대라고 불리고 있었지만, 성능적으로는 대폭으로 깎인 물건이었습니다.

예를 들어 GeForce의 특징적 기능이었던 NVIDIA 섀도우 맵(PCF)이 Tegra2/3에는 탑재되어 있지 않습니다. 그뿐 아니라 지금까지 테스트한 GPU 중에서는 Tegra2/3만이 24비트 깊이나 깊이 텍스처에 대응하지 않았습니다. 다른 회사의 GPU인 Adreno, PowerVR, Mali, Vivante 는 모두 이러한 확장기능에 대응하고 있었는데 말입니다.

위 사이트의 슬라이드 사진을 보면 Tegra4에서 드디어 기능차가 해소되었으며, 또한 하드웨어 PCF가 탑재되는 등, 기대했던 GeForce 6800/7800 클래스의 GPU가 된 것 같습니다.

대충 4 픽셀 파이프니 성능적으로는 아마도 아무 표시없는 GeForce 6800 정도가 아닐까 합니다. 픽셀 레이트는 PS3/Xbox360 세대의 절반이지만, 메모리 대역으로 봐도 납득할 수 있는 수치입니다.

Xbox360  22.4GB/s (+32.0GB/s)
PS3      22.4GB/s (+25.6GB/s)
Tegra4   14.9GB/s

물론 예상에 지나지 않으므로 실제로 입수할 때까지는 진짜 성능은 알 수 없습니다.

CPU/GPU 양쪽의 세대교체를 통해, 일점집중형에서 평균적인 성능향상으로 이동하고 있다고 생각할 수 있습니다. 아마도 극단적인 개성연출은 줄어들어가지 않을까 싶습니다.

컨솔과의 비교

Xbox1/GC 시대의 컨솔은 확실히 넘어섰습니다. 우선 CPU의 속도에서 단위가 다르고, GPU 성능도 셰이더 등은 훨씬 고성능입니다. 단, 필레이트에 특화된 PS2의 특수한 하드웨어는 올바르게 비교할 수 없습니다.

또 모바일 기기에 요구되는 해상도는 컨솔보다도 높으므로, 그 점도 고려할 필요가 있습니다.

          mem B/W                CPU          RAM    screen
---------------------------------------------------------------
GC        2.6GB/s (+?)           0.5GHz x1    24MB   SD 480
PS2       3.2GB/s (+48.0GB/s)    0.3GHz x1    32MB   SD 480
Xbox1     6.4GB/s                0.8GHz x1    64MB   SD 480
Xbox360  22.4GB/s (+32.0GB/s)    3.2GHz x3   512MB   HD 720
PS3      22.4GB/s (+25.6GB/s)    3.2GHz x7   512MB   HD 720
PS4     176.0GB/s                ?.?GHz x8     8GB   HD 1080

Tegra3    6.0GB/s                1.7GHz x4  1~2GB
APQ8064   8.5GB/s                1.7GHz x4           HD 1080
A5X      12.8GB/s                1.0GHz x2     1GB   HD 1536
Tegra4   14.9GB/s                1.9GHz x4
A6X      17.0GB/s                1.?GHz x2     1GB   HD 1536

누가 봐도 확실하게 다른 점이라면 RAM 용량이 있습니다. 스마트폰도 태블릿도 RAM 용량 1GB~2GB는 당연하게 되었으며, 이 점에서는 현행 컨솔보다도 여유가 있습니다.

실 기기에서의 CPU 속도

실재 기기에서의 성능 비교
(실측이 아니라 스펙을 통한 연산치이므로 주의)

                             CPU           Clock  DMIPS/clock  DMIPS*core
-------------------------------------------------------------------------
Nexus 10            Exynos 5 Cortex-A15 x2  1.7GHz   3.5          11.90
ARROWS X F-02E      Tegra3   Cortex-A9  x4  1.7GHz   2.5          17.00
Optimus G Pro L-04E APQ8064  Krait      x4  1.7GHz   3.3          22.44

Xbox360             Xenon    PPC core   x3  3.2GHz   2.0~(3.2)   19.20~(30.72)
  • DMIPS*core 가 통합성능(참고치)으로 수치가 높은 쪽이 빠름

CPU의 코어수가 다르면 비교가 어려워지므로 어디까지나 참고치로만 봐주시기 바랍니다. DMIPS/clock는 동일 클럭에서 비교한 코어 1개의 능력으로, 이것을 클럭*코어수로 곱한 것이 DMIPS*core가 됩니다.

Xbox360의 DMIPS/clock은 Wikipedia Instructions per second를 참조했습니다. 단 동일 성능이어야 할 PS3 PPE가 3.2이므로 Xbox360의 실제 점수는 더 높을 가능성이 있습니다. (괄호 안의 수치는 3.2를 기준으로 한 경우) PS3의 Cell은 특수하여 간단히 비교할 수 없습니다.

앞으로 등장하게 될 Exynos 5 Octa (Cortex-A15 x4)나 Tegra4 (Cortex-A15 x4)의 점수를 예상하면 다음과 같습니다.

                             CPU           Clock  DMIPS/clock  DMIPS*core
-------------------------------------------------------------------------
Exynos 5 Octa                Cortex-A15 x4  1.6GHz   3.5          22.40
Tegra4                       Cortex-A15 x4  1.9GHz   3.5          26.60

그다지 엄밀한 비교는 아닐지도 모르지만, CPU 능력으로 현행 컨솔에 필적하는 레벨에 달했다는 것은 사실입니다.

단, 단정밀도의 부동소수점 연산능력으로는 당해내지 못합니다.

          CPU                fp-op/core   core   clock    GFLOPS
----------------------------------------------------------------
Xbox360   Xenon PPC            12         3      3.2GHz   115.2
PS3       Cell BE              12+8       1+7    3.2GHz   217.6
          Tegra3 Cortex-A9     4          4      1.7GHz    27.2
          APQ8064 Krait        8          4      1.7GHz    54.4
          Tegra4 Cortex-A15    8          4      1.9GHz    60.8
  • GFLOPS가 높은 쪽이 빠름
  • 이론치이므로 이대로의 성능이 나오지는 않습니다.

특히 Cell이 압도적으로, 필레이트 괴물이었던 PS2와 마찬가지로 일부분(부동소수점 연산능력)에 있어서 특출난 능력을 갖고 있습니다.

예상으로는 아마 PS4에서도 CPU 하나의 부동소수점 연산능력에 있어서는 Cell에 미치지 못하지 않을까 싶습니다. 그 대신 GPU에 스트림 처리를 맡길 수 있으므로, GPU를 보조하던 Cell과는 반대 입장이 됩니다.

GPU의 속도

  • Mobile Device는 해상도가 매우 높음
  • GPU의 구조가 다름
  • Tegra는 연산정밀도가 다름
  • 성능면에서는 동등

스마트폰에서는 Full HD, 태블릿에서는 2048x1536나 2560x1600 등 상당한 고해상도화가 이루어지고 있습니다. 메모리 대역도 셰이더 사이클도 대부분 픽셀에 소비됩니다. 그 때문에 설령 GPU 성능이 높아져도 상대적으로는 파워 부족에 빠지게 됩니다.

태반의 GPU가 타일 기반이며, 데스크탑 GPU와 구조가 다릅니다. 특히 PowerVR은 아무 것도 하지 않아도 하드웨어가 지연 렌더링을 하므로, 소프트웨어에서 너무 복잡한 일을 하면 역효과가 될 가능성이 있습니다.

예를 들어 Early Z Culling을 효과적으로 사용하려면 앞쪽에서부터 묘화를 해야하지만, 픽셀 단위로 프래그먼트가 제거되는 TBDR(Tile-Based Deferred Rendering. 타일 기반 지연 렌더링)에서는 불필요합니다. 또 포스트 이펙트같이 프레임 버퍼를 재이용하면 추가 비용이 발생할 가능성이 있습니다. 이런 것들을 의식하면서 만들지 않았을 경우, 단순히 이식하는 것만으로는 모바일 GPU에서는 성능이 그다지 나오지 않을지도 모릅니다.

그 점에서 Tegra는 Immediate Mode이므로 데스크탑 GPU와 같은 사고방식이 통용됩니다. 실제로 테스트한 것은 아니므로 억측이지만, 위에 적은대로 Tegra4에서 대충 현행 컨솔의 절반 정도가 아닐까 생각됩니다.

다만 Tegra 시리즈의 픽셀 셰이더는 연산정밀도가 mediump입니다. 정밀도가 필요한 셰이더는 동작하지 않을 가능성이 있고, 하드웨어 섀도우 샘플러의 대응은 필연이었을지도 모릅니다. 또 mediump를 기준으로 하면 PowerVR 역시 퍼포먼스가 올라가므로, fp32인 GPU와의 단순 FLOPS 비교는 무리가 있다고 생각합니다.

참고로, Qualcomm의 Adreno는 픽셀 셰이더의 연산정밀도도 GPU 선능도 컨솔과 비교하여 손색이 없습니다.

  • 셰이더나 확장기능 등, GPU 성능은 현행 컨솔과 완전히 동등
  • 묘화속도에서는 근거가 될 데이터가 부족(하지만 아마도 뒤떨어질듯)

정리

결론을 내자면, 내부구조를 숙지하고 있는 것도 실측해본 것도 아니므로 근거가 없지만, GPU 성능이나 게임에서 중요한 단정밀도의 부동소수점 연산성능에서도 Xbox360/PS3 쪽이 위일 것입니다. 더욱이 고해상도라는 것이나 버스 대역의 한계도 있어, 실제 애플리케이션에서는 GPU 성능 이상으로 간격이 생기는 것이 현실이 아닐까 싶습니다. 다만 급격한 성능의 향상으로, 따라잡는 것도 시간의 문제라는 것은 확실합니다. 특히 램 용량에서 앞서고 있으며, CPU 의 실행성능도 차이가 없어지고 있으니까요.


원문 - scope(exit) in C++11

사실 매우 간단하므로 원문을 보시면 금방 아실거라고 생각합니다만, D 언어의 scope(exit)를 C++11의 람다와 auto를 이용하여 구현한 것입니다. BOOST에도 비슷한 것이 있지만 C++11의 기능을 이용하여 더 쉽고 간단하네요.

처음에는 std::function을 사용했지만, std::function이 꽤나 느리고(RTTI를 사용하기 때문이라고 하는군요), 템플릿 인수를 넣어줘야 하기 때문에(원문에는 없었지만 VC++10에서는 그러면 컴파일이 안되더라는...) 대신 템플릿을 이용한 것을 추천합니다.

template<typename F>
class ScopeExit
{
public:
     ScopeExit(F f) : m_f(f) {}
     ~ScopeExit() { m_f(); }

private:
     F m_f;
};

생성자에서 함수를 저장했다가 소멸자에서 호출하는, 더이상 할 말이 없을 정도로 간단한 클래스입니다. 여기서 더 간단히 쓰기 위해서 매크로와 헬퍼 함수를 추가합니다

// AutoScope 객체를 생성하기 위한 헬퍼
template<typename F>
ScopeExit<F> MakeScopeExit(F f)
{
     return ScopeExit<F>(f);
};

// 한번더 거치지 않으면 ScopeExit___LINE__이라는 이름의 변수가 생성됨
#define STRING_JOIN2(arg1, arg2)          DO_STRING_JOIN2(arg1, arg2)
#define DO_STRING_JOIN2(arg1,arg2)     arg1 ## arg2
#define MAKE_SCOPE(code)\
     auto STRING_JOIN2(ScopeExit_, __LINE__) = MakeScopeExit([&]()(code;))

MAKE_SCOPE 매크로를 사용하여 코드를 적어주면, 'ScopeExit_행번'이라는 이름의 ScopeExit 객체가 생성됩니다. __LINE__을 이용하므로 같은 행에 두 번 이상쓸 수는 없습니다만... 아마 그렇게 쓰는 분은 안계실 거라고 믿겠습니다.
원문에서는 캡쳐시 값으로 넘기고 있는데... 일단 여기서는 참조로 넘기고 있습니다. 적당히 취향에 맞춰서 바꾸면 될 듯 하네요(리플에서도 싸우고 있...)

사용 예시는 다음과 같습니다.

class Test
{
public:
     Test() { std::cout << "Test class constructed" << std::endl; }
     ~Test() { std::cout << "Test class destructed" << std::endl; }
};

int main()
{
     {
          Test* test = new Test;
          SCOPE_EXIT(delete test);
     }
     getchar();
     return 0;
}


이 문서는 CodeZine의 C++11 : スレッド・ライブラリひとめぐり을 번역한 것입니다. 이 글의 저작권은 CodeZine과 επιστημη 씨에게 있습니다. 이 기사에 실린 코드는 실제로 테스트해본 것이 아니므로, 옮겨적는 도중의 오타등으로 실제로 실행되지 않을 가능성이 있습니다.

C++11 : 스레드 라이브러리 둘러보기

C++11이 제공하는 스레드 라이브러리의 사용성을, Visual Studio 2012 RC에서의 시운전을 겸해 간단하게 체험해봅시다.

5월말, Visual Studio 2012 RC가 릴리즈되었습니다. 뼛속까지 C++꾼인 제게 가장 큰 흥미의 대상은 Visual C++ 2012 RC (이하 VC11)입니다. 현 Visual C++ 2010 (VC10)는 lambda 등의 국제표준 C++11의 일부에 대응하고 있지만, VC11 에서는 대응 범위가 더욱 넓어졌습니다. 이번에는 VC11++ 에서 새롭게 추가된 표준 스레드 라이브러리를 소개해보겠습니다.

10만 미만의 소수는 몇개나 있나?

「1과 그 자신 이외의 약수를 갖지 않는 수」가 소수입니다. 다시 말해 「2 이상 n 미만의 모든 수로 n을 나누어 떨어지지 않는다면, n은 소수」가 되겠지요. 그러므로 n이 소수인지 아닌지를 판정하는 함수는 이런 느낌입니다.

  1. // n은 소수?
  2. bool is_prime(int n) {
  3.    for ( int i = 2; i < n; ++i ) {
  4.       if ( n % i == 0 ) {
  5.          return false;
  6.       }
  7.    }
  8.    return true;
  9. }

이 is_prime 을 사용하여 「lo 이상 hi 미만의 범위에 있는 소수의 수」를 구하는 함수 count_prime은

  1. // lo 이상 hi 미만의 범위에 소수는 몇개인가?
  2. int count_prime(int lo, int hi) {
  3.    int result = 0;
  4.    for ( int i = lo; i < hi; ++i ) {
  5.       if ( is_prime(i) ) {
  6.          ++result;
  7.       }
  8.    }
  9.    return result;
  10. }

10만 미만의 소수를 감정해봅시다.

  1. /*
  2.  * M 미만의 소수가 몇개인가?
  3.  */
  4. void single(int M) {
  5.    chrono::system_clock::time_point start = chrono::system_clock::now();
  6.    int result = count_prime(2,M);
  7.    chrono::duration<double> sec = chrono::system_clock::now() - start;
  8.    cout << result << ' ' << sec.count() << "[sec]" << endl;
  9. }
  10. int main() {
  11.    const int M = 100000;
  12.    single(M);
  13. }
  14. /* 실행결과:
  15. 9592 1.64009[sec]
  16. */

10만까지의 정수에는 1만이 좀 안되는 소수가 있었습니다. 제 머신(i7-2700K, Windows7-64bit)에서는 약 1.6초만에 답을 내놓아주었습니다.

0 : Windows API

이 계산을 멀티스레드를 통한 고속화를 시도해보겠습니다. 전략은 아주 간단합니다. 소수인지 아닌지 판정할 범위 [2,M) (2이상 M 미만, M=100000)을 스레드수로 등분합니다. 예를 들어 스레드가 2개라면 [2,M/2) 과 [M/2,M) 으로. 이렇게 각 스레드로 분할된 범위에서 소수의 감정을 분담시켜, 각 결과를 전부 더하면 OK, 라는 것입니다.

우선 Windows API 로 구현하겠습니다. 범위 [lo,hi) 를 n등분하는 클래스 div_range를 준비합니다.

  1. #ifndef DIV_RANGE_H_
  2. #define DIV_RANGE_H_
  3.  
  4. // [lo,hi) 를 n등분한다
  5. template<typename T =int>
  6. class div_range {
  7. private:
  8.    T lo_;
  9.    T hi_;
  10.    T stride_;
  11.    int n_;
  12. public:
  13.    div_range( T lo, T hi, int n )
  14.       : lo_(lo), hi_(hi), n_(n) { stride_ = (hi-lo)/n; }
  15.    T lo(int n) const { return lo_ + stride_ * n; }
  16.    T hi(int n) const { return (++n < n_) ? lo + stride_ * n : hi_; }
  17. };
  18.  
  19. #endif

분할된 범위별로 스레드를 만들어, 모든 스레드가 완료된 시점에서 정산합니다.

  1. /* Win32 thread 를 위한 wrapper */
  2.  
  3. // <0>:loi, <1>:hi, <1>:result
  4. typedef tuple<int,int,int> thread_io;
  5.  
  6. DWORD WINAPI thread_entry(LPVOID argv) {
  7.    thread_io& io = *static_cast<thread_io*>(argv);
  8.    get<2>(io) = count_prime(get<0>(io), get<1>(io));
  9.    return 0;
  10. }
  11.  
  12. /*
  13.  * M 미만의 소수는 몇개인가?
  14.  */
  15. void multi(int M, int nthr) {
  16.    vector<HANDLE> handle(nthr);
  17.    vector<thread_io> io(nthr);
  18.    div_range<> rng(2,M,nthr);
  19.    for ( int i = 0; i < nthr; ++i ) {
  20.       io[i] = thread_io(rng.lo(i), rng.hi(i), 0);
  21.    }
  22.  
  23.    chrono::system_clock::time_point start = chrono::system_clock::now();
  24.    for ( int i = 0; i < nthr; ++i ) {
  25.       handle[i] = CreateThread(NULL, 0, &thread_entry, &io[i], 0, NULL);
  26.    }
  27.    WaitForMultipleObjects(nthr, &handle[0], TRUE, INFINITE);
  28.    chrono::duration<double> sec = chrono::system_clock::now() - start;
  29.  
  30.    int result = 0;
  31.    for ( i = 0; i < nthr; ++i ) {
  32.       CloseHandle(handle[i]);
  33.       result += get<2>(io[i]);
  34.    }
  35.    cout << result << ' ' << sec.count() << "[sec] : " << nthr << endl;
  36. }
  37.  
  38. int main() {
  39.    const int M = 100000;
  40.    for ( int i = 0; i < M; ++i ) multi(M, i);
  41. }
  42.  
  43. /* 실행결과:
  44. 9592 1.6651[sec] : 1
  45. 9592 1.21607[sec] : 2
  46. 9592 0.970055[sec] : 3
  47. 9592 0.752043[sec] : 4
  48. 9592 0.631036[sec] : 5
  49. 9592 0.52903[sec] : 6
  50. 9592 0.549031[sec] : 7
  51. 9592 0.497028[sec] : 8
  52. 9592 0.470027[sec] : 9

스레드 수 1~9 에서 실행시켜보니, 8개의 논리 코어를 가진 i7에서는 당연하지만 스레드 8개 정도에서 스피드가 한계에 부딪힙니다. 3배 정도 빨라졌군요. Windows API로 구현할 경우, 스레드의 본체인 count_prime 을 스레드에 올리기 위한 wrapper (이 샘플에서는 thread_io 와 thread_entry)가 필요합니다.

1 : thread

그럼 C++11 의 스레드 라이브러리를 사용한 버전을 봅시다.

  1. void multi(int M, int nthr) {
  2.    vector<thread> thr(nthr);
  3.    vector<int> count(nthr);
  4.    div_range<> rng(2,M,nthr);
  5.  
  6.    chrono::system_clock::time_point start = chrono::system_clock::now();
  7.    for ( int i = 0; i < nthr; ++i ) {
  8.       thr[i] = thread([&,i](int lo, int hi) { count[i] = count_prime(lo,hi); }, rng.lo(i), rng.hi(i));
  9.    }
  10.    int result = 0;
  11.    for ( int i = 0; i < nthr; ++i ) {
  12.       thr[i].join();
  13.       result += count[i];
  14.    }
  15.    chrono::duration<double> sec = chrono::system_clock::now() - start;
  16.  
  17.    cout << result << ' ' << sec.count() << "[sec] : " << nthr << endl;
  18. }
  19.  
  20. int main() {
  21.    const int M = 100000;
  22.    for ( int i = 1; i < 10; ++i ) multi(M, i);
  23. }

어떻습니까? Windows API를 통한 구현과 비교하면 훨씬 간단하여, std::sthread의 생성자에 스레드의 진입점과 인수를 넣어주는 것만으로 스레드가 생성되어 움직입니다. 나머지는 join() 으로 완료되기를 기다리는 것 뿐.

생성자에 넘길 스레드 진입점은 ()로 된 것, 즉 함수자라면 뭐든 OK입니다.

  1. void count_prime_function(int lo, int hi, int& result) {
  2.    result = count_prime(lo, hi);
  3. }
  4.  
  5. class count_prime_class {
  6.    int& result_;
  7. public:
  8.    count_prime_class(int& result) : result_(result) {}
  9.    void operator()(int lo, int hi) { result_ = count_prime(lo, hi); }
  10. };
  11.  
  12. void multi(int M) {
  13.    thread thr[3];
  14.    int count[3];
  15.    div_range<> rng(2,M,3);
  16.  
  17.    auto count_prime_lambda = [&](int lo, int hi) { count[2] = count_prime(lo,hi); };
  18.  
  19.    chrono::system_clock::time_point start = chrono::system_clock::now();
  20.    // 함수 포인터, 클래스 인스턴스, lambda식으로 스레드를 작성
  21.    thr[0] = thread(count_prime_function,        rng.lo(0), rng.hi(0), ref(count[0]));
  22.    thr[1] = thread(count_prime_class(count[1]), rng.lo(1), rng.hi(1));
  23.    thr[2] = thread(count_prime_lambda,          rng.lo(2), rng.hi(2));
  24.    for ( thread& t : thr ) t.join();
  25.    chrono::duration<double> sec = chrono::system_clock::now() - start;
  26.  
  27.    cout << count[0] + count[1] + count[2] << ' ' << sec.count() << "[sec]" << endl;
  28. }

2 : async/future

thread 를 사용하면서 join()을 통해 완료를 기다린 후 결과를 참조(읽기)하고 있습니다만, async/future를 사용하면 완료 대기와 결과 참조가 간략화됩니다. 리턴값(결과)를 돌려주는 함수자와 인수를 async에 넘겨주면 future가 리턴됩니다. 그 future에 대해 get() 하는 것만으로 완료 대기와 결과 참조를 같이 할 수 있습니다.

  1. class count_prime_class {
  2. public:
  3.    int operator()(int lo, int hi) { return count_prime(lo, hi); }
  4. };
  5.  
  6. void multi(int M) {
  7.    future<int> fut[3];
  8.    div_range<> rng(2,M,3);
  9.  
  10.    auto count_prime_lambda = [&](int lo, int hi) { return count_prime(lo,hi); };
  11.  
  12.    chrono::system_clock::time_point start = chrono::system_clock::now();
  13.    // 함수 포인터, 클래스 인스턴스, lambda식으로 future를 작성
  14.    fut[0] = async(count_prime,         rng.lo(0), rng.hi(0));
  15.    fut[1] = async(count_prime_class(), rng.lo(1), rng.hi(1));
  16.    fut[2] = async(count_prime_lambda,  rng.lo(2), rng.hi(2));
  17.    int result = fut[0].get() + fut[1].get() + fut[2].get();
  18.    chrono::duration<double> sec = chrono::system_clock::now() - start;
  19.  
  20.    cout << count[0] + count[1] + count[2] << ' ' << sec.count() << "[sec]" << endl;
  21. }

3 : mutex/atomic

1 : thread 에서 사용한 코드를 조금 바꿔보겠습니다. lo 이상 hi 미만의 소수를 감정하는 coutn_prime을 전부 없애버리고, lambda 내에서 직접 처리하게 해보겠습니다.

  1. void multi(int M, int nthr) {
  2.    vector<thread> thr(nthr);
  3.    div_range<> rng(2, M, nthr);
  4.  
  5.    int result = 0;
  6.  
  7.    chrono::system_clock::time_point start = chrono::system_clock::now();
  8.    for ( int t = 0; t < nthr; ++t ) {
  9.       thr[t] = thread([&](int lo, int hi) {
  10.          for ( int n = lo; n < hi; ++n ) {
  11.             // n이 소수라면 result에 1을 더함
  12.             if ( is_prime(n) ) {
  13.                ++result;
  14.             }
  15.          },
  16.          rng.lo(t), rng.hi(t));
  17.    }
  18.    for ( thread& th : thr ) { th.join(); }
  19.    chrono::duration<double> sec = chrono::system_clock::now() - start;
  20.  
  21.    cout << result << ' ' << sec.count() << "[sec] : " << nthr << endl;
  22. }

잘 굴러갈 것 같…지만, 여기에는 커다란 함정이 있습니다. n이 소수일때 ++result 하고 있는데, ++result 는 result 를 읽고 「1을 더해서/쓰고 돌려주는 처리」를 합니다. 읽고 나서 쓰고 돌려줄 때까지의 사이에 다른 스레드가 끼어들면 result 의 결과가 이상해집니다. 이것을 data-race(자료 경합)이라고 부르며, 위태로운 타이밍에 발생하기에 재현하기가 어려운 상당히 까다로운 버그입니다. 이런 때에 「여기서 여기까지, 다른 스레드는 들어오지 마(밖에서 기다려)!」를 실현하는 것이 mutex(mutual exclusion : 상호배타) 입니다. mutex 를 lock() 한 후 unlock() 할 때까지, 다른 스레드는 lock() 지점에서 블럭됩니다. 위의 예시를 제대로 움직이려면

  1. ...
  2. mutex mtx;
  3. int result = 0;
  4. ...
  5.    // n이 소수라면 result에 1을 더함
  6.    if ( is_prime(n) ) {
  7.       mtx.lock();
  8.       ++result;
  9.       mtx.unlock();
  10.    }
  11. ...

혹은

  1. ...
  2. mutex mtx;
  3. int result = 0;
  4. ...
  5.    // n이 소수라면 result에 1을 더함
  6.    if ( is_prime(n) ) {
  7.       lock_guard<mutex> guard(mtx);
  8.       ++result;
  9.    }
  10. ...

lock_guard는 생성될 때 lock()/파괴될 때 unlock() 해주므로 unlock() 하는 것을 잊어버릴 위험이 없어 편합니다. 도중에 예외가 발생해도 확실하게 unlock() 해주고요.

또, int, long 등 내장 타입 및 포인터 타입에 대해서 ++, --, +=, -=, &=, |= 등의 연산을 행하는(극히 짧은) 동안만 다른 스레드의 끼어들기를 억지할 때에는 고속/경량인 atomic 을 추천합니다. 위의 예시라면

  1. ...
  2. atomic<int> result = 0;
  3. ...
  4.    // n이 소수라면 result에 1을 더함
  5.    if ( is_prime(n) ) {
  6.       ++result;
  7.    }
  8. ...

로 OK입니다.

4 : contition_variable

condition_variable 을 사용하여 한 스레드에서 다른 스레드 이벤트를 던질 수 있습니다. 이벤트를 기다리는 스레드에서는

  1. mutex mtx;
  2. condition_variable cv;
  3.  
  4. unique_lock<mutex> lock(mtx);
  5. ...
  6. cv.wait(lock);
  7. ...

condition_variable에서 wait() 하면 lock 된 mutex를 일단 풀고(unlock 하고) 대기 상태가 됩니다. 이벤트를 송출할 스레드에서는

  1. unique_lock<mutex> lock(mtx);
  2. ...
  3. cv.notify_all();
  4. ...

condition_variable에 notify_all (또는 notify_one) 하면 대기하는 쪽의 wait()가 풀림과 동시에 mutex가 다시 lock 되는 구조입니다.

이것을 이용해서 소수를 감정하고 있는 모든 스레드의 완료를 기다려보겠습니다.

  1. void multi(int M, int nthr) {
  2.    vector<thread> thr(nthr);
  3.    div_range<> rng(2,M,nthr);
  4.    condition_variable cond;
  5.    int finished = 0;
  6.    atomic<int> result = 0;
  7.    mutex mtx;
  8.  
  9.    chrono::system_clock::time_point start = chrono::system_clock::now();
  10.    for ( int t = 0; t < nthr; ++t ) {
  11.       thr[t] = thread([&](int lo, int hi) {
  12.             for( int n = lo; n < hi; ++n ) {
  13.                if( is_prime(n) ) ++result;
  14.             }
  15.             lock_guard<mutex> guard(mtx);
  16.             ++finished;
  17.             cond.notify_one();
  18.          },
  19.          rng.lo(t) rng.hi(t));
  20.    }
  21.    unique_lock<mutex> lock(mtx);
  22.    // 모든 스레드가 ++finished 해서 finished == nthr 이 되는 것을 기다림
  23.    cond.wait( lock, [&]() { return finished == nthr; } );
  24.    chrono::duration<double> sec = chrono::system_clock::now() - start;
  25.  
  26.    cout << result << ' ' << sec.count() << "[sec] : " << nthr << endl;
  27.    for( thread& th : thr ) { th.join(); }
  28. }

condition_variable 을 사용한 예를 하나 더 들어보겠습니다. 랑데부(rendezvous) 혹은 배리어(barrier) 라고 불리는 「대기」 구조입니다.

  1. class rendezvous {
  2. public:
  3.    rendezvous(unsigned int count)
  4.       : threshold_(count), count_(count), generation_(0) {
  5.       if ( count == 0 ) { throw std::invalid_argument("count cannot be zero."); }
  6.    }
  7.  
  8.    bool wait() {
  9.       std::unique_lock<std::mutex> lock(mutex_);
  10.       unsigned int gen = generation_;
  11.       if ( --count_ == 0 ) {
  12.          generation_++;
  13.          count_ = threshold_;
  14.          condition_.notify_all();
  15.          return true;
  16.       }
  17.       condition_.wait(lock, [&]() { return gen != generation_; });
  18.       return false;
  19.    }
  20.  
  21. private:
  22.    std::mutex mutex_;
  23.    std::condition_variable condition_;
  24.    unsigned int threshold_;
  25.    unsigned int count_;
  26.    unsigned int generation_;
  27. };

rendezvous r(5); 처럼, 기다릴 사람 수(스레드 수)를 인수로 하는 생성자를 만듭니다. 각 스레드가 r.wait() 하면 전원이 모일때까지 대기 상태가 되어, 마지막 스레드가 r.wait() 하는 순간 전원의 블럭이 풀려 일제히 움직이기 시작합니다.

앞서 본 모든 스레드 완료 대기를 rendezvous 로 구현하면,

  1. void multi(int M, int nthr) {
  2.    vector<thread> thr(nthr);
  3.    div_range<> rng(2,M,nthr);
  4.    atomic<int> result = 0;
  5.    rendezvous quit(nthr+1);
  6.  
  7.    chrono::system_clock::time_point start = chrono::system_clock::now();
  8.    for ( int t = 0; t < nthr; ++t ) {
  9.       thr[t] = thread([&](int lo, int hi) {
  10.             for( int n = lo; n < lo; ++n ) {
  11.                if ( is_prime(n) ) ++result;
  12.             }
  13.             quit.wait();
  14.          },
  15.          rng.lo(t), rng.hi(t));
  16.    }
  17.    quit.wait(); // 모든 스레드가 wait 할때까지 기다림
  18.    chrono::duration<double> sec = chrono::system_clock::now() - start;
  19.  
  20.    cout << result << ' ' << sec.count() << "[sec] : " << nthr << endl;
  21.    for ( thread& th : thr ) { th.join(); }
  22. }

C++11 이 제공하는 스레드 라이브러리를 간단하게 소개해봤습니다. 어떻습니까? 멀티스레드 애플리케이션을 훨씬 간단하게 작성할 수 있게 되었습니다. CPU 미터가 모든 코어를 채우는 High Performance Computing 의 쾌감을 즐겨보시길.

이 글은 스프링노트에서 작성되었습니다.

원문

니시카와 젠지의 3D 게임 팬을 위한 차세대 PSP - GPU 강좌

"타일 기반 지연 렌더링(Tile Based Deferred Rendering"이란 무엇인가?

소니 컴퓨터 엔터테인먼트의 차세대 휴대 게임기가 될 것으로 예상되는……본 기사에서는 가칭「PSP2」라고 해두지만, 해외 사이트 등에서는 한때 「PSP2의 GPU로 SGX543MP4이 쓰인다!」고 소란스러웠던 적이 있었다.

그것이 사실인지 아닌지 확인할 방법은 없지만, 「PowerVR」이라고 하면 iPhone 3GS도「PowerVR」이니 설마?……하는 꿈이 퍼지는 것도 당연할 것이다.

GPU라고 하면 「NVIDIA인가 ATI(AMD)인가」하는 것이 요즘에, 분야는 다르다고 하지만 최근 들어 대두되고 있는 「PowerVR」에 관해서 알아보는 것도 나쁘지 않다고 생각하여, GDC 기간 중에 출전했던 「PowerVR」 개발원 Imagination Technologies Group의 부스에 찾아가 보았다. 그랬더니 다행히도 최신 「PowerVR」에 관한 기본자료를 받을 수 있었기에, 이것을 읽어보면서 「PowerVR」이 어떤 물건인지 이해해보도록 하겠다.

「PowerVR」이라고 하면, 게임 팬에게 있어 친숙한 것은 드림캐스트에 채용되었던 「PowerVR2」일 것이다. 그 시대에는 아직 텍스처를 붙이는 것과 극히 기본적인 조명처리만을 할 수 있었던 GPU로, 현재의 GPU의 모습과 비교하면 아직 많이 원시적인 모습이었다.

그럼, 최신의 「PowerVR」시리즈는 어떤 모습으로 진화해왔을까.

「PSP2」에 탑재된다는 소문이 있는 SGX543MP4의 시리즈인 「PowerVR SGX5」 시리즈를 주제로 그 속을 탐구해볼까 한다.

소문 속의 GPU는 어떤 물건?

본 기사의 대상은 주로 「PSP2(가칭)」에 탑재된다는 소문이 있는 SGX543MP4 시리즈로 하겠다.

「SGX543MP」의 MP는 멀티프로세서의 약자로, MP4는 4코어 프로세서라는 의미가 된다.

아키텍처상으로는 MP16의 16코어까지 대응할 수 있으며, NVIDIA의 SLI처럼 코어를 늘리면 늘릴 수록 퍼포먼스가 높아지는 구조로 되어있다. 각 코어는 긴밀하게 상호연대를 취하면서 병렬동작하므로, 1코어를 증가시킬 때만다 퍼포먼스가 90%는 상승한다고 한다. 멀티코어는 기수 코어에도 대응하므로 MP3같은 3코어 솔루션 등도 있다.

1코어 당 코어 면적은 2.6mm2, 16코어면 32mm2. PSP2용이라는 소문이 돌고 있는 MP4에서도 한편의 전용면적은 3mm 남짓한 것이 4개라는 극소 코어라는 이야기이다.

200MHz 동작시 4코어 당 스루풋은 초당 1억3300만 폴리곤, 초당 40억 픽셀정도라고 한다. MP4의 스펙을 과거의 PC용 GPU에 견주어보면, 픽셀 필레이트로 봐서 2003년의 NVIDIA의 울트라 하이엔드 GeForce FX 5900 Ultra(초당 36억 픽셀) 정도일까.

「SGX543」 시리즈의 대응 그래픽 API는 OpenGL/ES2.0(혹은 OpenGL/ES1.1+Extention Pack)으로, DirectX 세대로 말하자면 DirectX 9세대 프로그래머블 셰이더 3.0 사양(SM3.0)에 상당하는 포텐셜을 가진 것이 된다.

프로그래머블 셰이더 아키텍처로는 통합형 셰이더 아키텍처를 채용하고 있으며, 각 범용 셰이더 유닛은 정점 셰이더로, 혹은 픽셀 셰이더로 기용되거나 한다. 1코어 당 셰이더 유닛 수(파이프라인 수)는 4. MP4라면 4배인 16개가 된다.

PowerVR 아키텍처의 특별한 렌더링 방법이란?

「PowerVR」시리즈의 렌더링 엔진은 NVIDIA나 ATI의 GPU와는 달리, Z 버퍼를 이용하지 않는 방법을 채용하고 있다.

Z버퍼란, 가장 최근에 묘화한 (폴리곤을 구성하는) 픽셀 시점에서 본 깊이값을 기록하는 버퍼로, 폴리곤의 묘화순서가 엉망이라도, 묘화해갈 폴리곤군의 앞쪽과 안쪽의 관계성을 판별해가면서 묘화하는데 빼놓을 수 없는 구조이다.

「PowerVR」는 이 Z버퍼를 이용하지 않고 렌더링하는 것이 최대의 특징으로, 특히 이 수법을 「타일 기반 지연 렌더링(Tile Based Deferred Rednering)」(TBDR)이라고 부른다. 기본적인 개념으로서, TBDR은 반복묘화를 하지 않는다는 이점이 있다.

「타일 기반(Tile Based)」 부분은, 관리상 묘화 대상 화면을 적당한 타일(블럭)으로 분할하여 관리하는 것을 의미하며, 묘화 그 자체는 각 타일별로 1번 밖에 하지 않는다. 기본설정된 타일 사이즈는 16×16 픽셀이라고 하지만, GPU의 설정에서 바꿀 수도 있다고 한다.

그래픽 응용 프로그램(게임 엔진 등)에서 그 장면의 묘화 커맨드군이 들어오면, 그것을 해석하여 정점 셰이더 처리를 하고, 어느 폴리곤의 어느 부분이 어느 타일에 대응하는지를 산출해간다(폴리곤이 복수 타일에 걸쳐있을 경우도 있지만, 그것도 당연히 배려한다).

이때, 들어온 폴리곤이 이미 그 타일에 할당되어 있던 폴리곤보다도 안쪽에 있을 경우에는 가려졌다고 판단하여 제거한다(이미 그 타일에 할당되어 있던 폴리곤이 반투명이었을 경우에는 살아남는다).

이렇게 그 장면의 폴리곤이 모두 들어오면 묘화 페이즈로 이행된다.

묘화는 타일 단위로 병렬처리된다. GPU 코어측의 파이프라인이 복수 있으면 한번에 묘화되는 타일 수가 늘어난다……라는 이미지이다.

그럼 타일 내의, 어떤 픽셀을 그릴 때를 생각해보도록 하자.

그 픽셀에 할당되어있던 몇개인가의 폴리곤 중, 시점 방향에 대해 가장 가까운 폴리곤의 픽셀만 채택되어 픽셀 셰이더에서 픽셀 음영처리되어 묘화용으로 출력된다. 반투명이 포함된 경우에는 더욱 안쪽 방향에 있는 폴리곤의 픽셀 음영처리를 위해 다시 픽셀 셰이더가 가동되게 된다. 반투명이 포함되면 무거워지는 것은 「PowerVR」도 마찬가지인 것이다.

타일 단위로 처음 폴리곤의 할당이나 기초처리를 해버리고, 정점 단위의 조명처리는 물론 픽셀 단위의 조명까지를 나중으로(Deferred) 돌리므로 「타일 기반 지연 렌더링(Tile Based Deferred Rendering)」이라는 이름이 붙은 것이다.

「PowerVR」아키텍처의 이점은?

오른쪽 그림은 「PowerVR SGX5」시리즈의 내부 블럭 다이어그램이다.

「Vertex Data Master」는 폴리곤을 구성하는 정점 데이터를 갖춘 블럭, 「Coarse Grain Scheduler(CGS)」는 이후의 범용 셰이더 유닛 「Universal Scalable Shader Engine(USSE)」의 기용을 관리하거나 발주하거나 하는 블럭이다.

「Tiling Co-Processor」는 화면 좌표계로 변환된 폴리곤들을 타일에 할당하고, 실제 픽셀 렌더링을 위한 각종 준비를 하는 곳.

「Pixel Data Master」는 실제 픽셀 묘화를 위해 관련 데이터를 모아둔 블럭이다. 여기서 「CGS」를 거쳐 「USSE」의 범용 셰이더 유닛을 픽셀 셰이더로 기용하여 픽셀 음영처리를 한다. 「Texturing Co-Processor」는 텍스처 유닛이다. 출력된 픽셀 값은 Pixel Co-Processor에서 모아서 쓰게된다.

「TBDR」의 이점은,

  1. Z버퍼가 없어서 메모리 이용효율이 높다.
  2. Z버퍼 접근이 없으므로 버스 소비가 적다.
  3. 묘화순서를 신경쓰지 않아도 올바르게 반투명처리된다.

는 것 정도로, 1. 과 2. 에 관해서는 낮은 소비전력으로 이어진다. 이 절전성능이야말로 「PowerVR」이 요즘 휴대기기나 임베디드 기기로의 채률이 높아진 것과 연결된 원인이라고 할 수 있다.

그 대신, 일반적인 GPU 보다도 묘화가 되기 전의 계산량이 많아진다는 인상이 있다. 하지만 「메모리 접근이 많아지는 것보다는 낫다」라는 철학 하에, 「PowerVR」은 이 아키텍처를 지켜서 진화해온 것이다.

iPhone에서의 채용이 기폭제가 되어, 임베디드 기기용 GPU로서 일약 주목을 받게 된「PowerVR」. 정말로 「PSP2(가칭)」에 채용되게 될지는 모르지만, 앞으로 그 동향을 주목할 필요가 있을 듯 하다

원문

니시카와 젠지의 3D 게임 팬을 위한 그래픽스 강좌 [GDC 특별편]

NGP에 채용된 GPU의 개발원에게 듣는 PowerVR SGX543MP4+의 모든것
NGP보다도 신세대의 GPU가 빨리도 발표!?

iPhone 같은 스마트폰이나, iPad 같은 태블릿 단말에 채용되었고, 얼마 전에는 소니 컴퓨터 엔터테인먼트의 NGP(Next Generation Portable)에도 채용된 GPU라고 하면 PowerVR 시리즈다. 의외로 모르는 사람도 많은듯 하지만 인텔의 ATOM 베이스의 GMA500/GAM600이 PowerVR 기반이다. 다시 말해 PowerVR은 스마트폰이나 태블릿 만이 아니라, VAIO P나 VAIO X 같은 Windows 기반의 넷북 PC에도 채용되어 있다는 소리로, 현재 PowerVR 채용 하드웨어를 소지하고 있는 사람은 의외로 많다.

올드 게임팬에게 있어서는 「PowerVR = 드림캐스트의 GPU」라는 인식을 갖고 있는 사람도 적지 않을 것이라 생각하는데, 요즘에는 「소비전력 대 성능」중시의 하드웨어에 있어 거의 메인스트림이 되었다고 할 수 있는 GPU다.

올해의 GDC의 전시회장에서도 PowerVR 개발원인 Imagination Technologies가 부스를 출전하여, 기술쪽에 아주 자세한 PowerVR Graphics, Business Development의 Kristof Beets 씨와 Director of PR인 David Harold 씨와 인터뷰를 할 기회를 얻었기에, 그 결과 리포트를 전한다.

「TILE BASED DEFERRED RENDERING」이란 무엇인가?

NGP에 채용된 PowerVR SGX543MP4+ 만이 아니라, PowerVR 계열 GPU에서 공통적으로 이용되고 있는 기술이「TILE BASED DEFERRED RENDERING(TBDR)」이다.

상세한 내용은 「니시카와 젠지의 3D 게임 팬을 위한 차세대 PSP - GPU 강좌」에서 설명했으므로 이 것을 참조하면 알겠지만, 일반적인 GPU와는 달리 Z버퍼(심도 버퍼)를 사용하지 않고 렌더링하는 점을 특징으로 들 수 있다. 일반적인 3D 그래픽스 렌더링에서는 3D 오브젝트를 2D 공간(화면좌표계)에 사영하여, 그 2D 형태을 묘화하게 되는데, 이 때 이미 묘화된 화면을 겹쳐그리게 된다. 2D 형태으로 집어넣지만 그리려고 하는 것은 3D 세계이므로, 2D 형태에 들어갈 삼각형(폴리곤)의 전후판정을 할 필요가 있다. 이 판정에 이용되는 것이 픽셀 단위의 깊이값을 저장하는 Z버퍼의 내용이다.

다시 말해, 일반적인 3D 그래픽스 렌더링에서는 묘화할 3D 오브젝트가 늘어나면 그림이 겹쳐지게될 확률이 높아지고, Z버퍼에의 접근도 증가한다. 만약 전후판정의 결과, 그리지 않게 된다고 해도 Z버퍼 접근은 일어나므로 메모리 대역을 소비하게 된다. 메모리 대역을 소비하는 것은 소비전력의 증가로 이어진다.

그래서 TBDR에서는 묘화대상이 되는 화면을 적당한 블럭으로 나누어(TILE BASED), 각 블럭별로 이 전후관계의 판정을 먼저 처리한다. 그 후, 최종적인 조명과 셰이딩을 나중에 처리(DEFERRED RENDERING)하게 되는데, 이 처리는 전 단계의 블럭별로 GPU 코어 내에에서 병렬처리된다.

NGP에 채용된 SGX543의 예를 들자면, 각 코어에는 4기의 셰이더 유닛이 실장되어 있으며, 이것이 4코어 있으므로 각 타일의 렌더링은 4유닛×4코어=16기의 셰이더 유닛으로 병렬처리되게 된다.

앞에 나온 과거 연재기사에서는 각 블럭이 16×16 픽셀이라고 적었지만, 이에 관하여 Beets 씨는 이렇게 이야기했다. 「요즘의 PowerVR 계열 코어에서는 32×32 픽셀을 기본 블럭 사이즈로 하고 있다. 일단 조합될 비디오 메모리 용량 등이나 렌더링 해상도에 따라 블럭 사이즈를 변경가능하긴 하지만, 기본적으로 32×32 픽셀이라고 알아두면 된다」(Beets씨)

PowerVR 아키텍처를 감싼 의문

NGP에 채용된 SGX543는 “MP4” 사양으로 4코어이지만, 최대로는 MP16의 16코어까지 설정가능하게 되어 있다. 각 코어의 동작제어는 어떻게 되어있을까.

예를 들면, 몇개의 코어를 정점처리에 할당하고, 몇개의 코어를 픽셀 처리에 할당한다던가, NVIDIA의 SLI 처럼 렌더링할 프레임을 코어 별로 할당할 수 있을까.

「멀티코어 사양이 되어있을 경우에는, 완전히 하나로 통합된 하드웨어처럼 동작된다. 즉, 각 셰이더 유닛은 종류가 다른 작업(예를 들면, 정점처리 작업과 픽셀처리 작업의 조합 같은)을 동시에 담당하게 되는 경우가 있다. 각 작업에서 메모리 접근 스톨이 발생하면, 이것을 은폐하기 위해 작업 전환이 일어난다. 각 셰이더 유닛을 풀활용하기 위해서는 부하 밸런스 조정을 자동적 및 총괄적으로 처리할 필요가 있으므로, 각 코어를 용도 별로 배분하는 것은 불가능하며, 해서도 안된다.」(Beets 씨)

SGX5 시리즈는 GPGPU에도 대응한다. 예를 들어 미디어 처리나 물리 시뮬레이션 처리처럼, 명확하게 종류가 다른 GPGPU 작업이 혼재되어 있을 경우에는 어떨까.

「마찬가지다. 셰이더 유닛을 풀활용하기 위해서는 많은 종류의 작업을 실행시키는 편이 좋다. 실제로 PowerVR의 작업 스케쥴러는 설정가능하므로 기술적으로 불가능하지는 않다. 다만, 하나의 코어에 한 종류의 처리를 전담시키면 메모리 접근이 특정 장소에 집중되는 경향이 있다. 다른 종류의 작업을 섞어서 작업을 스위칭시키는 편이 메모리 접근의 인터리브 효과도 생겨나 효율이 좋다.」(Beets 씨)

또한, 멀티코어의 설정에서는 블럭 다이어그램에는 없는 상위 계층의 스케쥴러가 실장되어 있어, 여기서 각 코어에 대해 자동적으로 작업 배분을 하게 되어 있다고 한다.

NVIDIA의 SLI이나 AMD의 CrossFire 같은 단독 동작하는 GPU의 PCI-Express 버스에 달려있는 멀티 구동과는 달리, PowerVR 계열의 멀티코어의 경우에는 원칩 내에서의 멀티 구동이 되므로, 처음부터 멀티 구동을 전제로 한 논리설계가 되어 있다. 따라서, “방법”으로서는 멀티코어 GPU라기보다는 싱글코어 GPU에 가깝다고 할 수 있다.

예를 들어, 가벼운 작업을 실행하고 있을때는 1코어, 3D 그래픽스 렌더링을 처리할 때에는 4코어……라는 식으로 코어의 유효화와 무효화를 코어 단위로 제어하는 것은 가능할까?

「기술적으로는 가능하고, SoC에서 PowerVR을 집어넣을때 그런 제어를 넣는 것도 가능할 것이다. 다만, PowerVR 아키텍처는 원래 절전성능이 우수한 아키텍처이다. 예를 들어 1코어에 딱 맞는 부하의 작업이 있다고 해도, 4코어 중 1코어만 움직이게 하고 남은 3코어를 꺼두는 것과, 4코어 전체로 순식간에 끝내버리고 4코어를 휴면상태로 하는 것은 소비전력에 있어 큰 차이가 없다.」(Beets씨)

NGP에 채용된 PowerVR SGX543MP4+에 있어서 "+"의 의미는?

NGP의 GPU에 관해서 자주 오르는 화제에 「SGX543MP4+의 "+"는 무슨 의미?」라는 것이 있다.

David Harold 씨는 이 의문에 대해 이렇게 답했다.

「소니 컴퓨터 엔터테인먼트는 우리에게서 PowerVR SGX543MP4의 IP를 구입한 것으로, 실제 칩, SoC를 구성하는 것은 그들 자신이다. 그들이 우리의 IP를 어떻게 개량할지는 우리들이 알 수가 없다. 소니는 지금까지 오랫동안 게임 업계에 있어왔고, 그래픽 프로세서에 관한 노하우도 상당히 갖고 있으므로 게임 대상의 독자적인 개량이 행해질 것이다.」(Harold 씨)

참고로, 필자의 취재에 의하면 이 "+"부분에 그다지 커다란 의미는 없는 느낌이었다. 구체적으로는, 아마도 OpenGL ES 2.0 사양에는 없는 독자적인 기능을 제공하거나, 포맷 등을 지원하는 정도일 것이라 생각된다.

예를 들면, HDR 렌더링에 있어서 최신의 PC용 GPU에서는 각 채널 16비트의 부동소수점(FP16)의 64비트 버퍼가 표준적으로 사용되고 있지만, 이것은 버스폭 64비트의 SGX543 계열에서의 사용에는 적합하지 않다. 따라서, NGP 용의 SGX543MP4"+"에서는 32비트에서 나름대로 높은 다이나믹 레인지를 발휘하는 9995 버퍼같은 것이 지원된다고 한다. 각 RGB가 9비트, 5비트에는 각 RGB에 대한 공통지수항이 저장되어, 그 포맷을 텍스처만이 아니라 렌더링 타겟으로 이용할 수 있는 듯 하다.

TILE BASED DEFERRED RENDERING에 관한 의문

TBDR에 관한 의문점에서 상당히 많았던 것이 반투명 오브젝트의 렌더링에 관한 것으로, 그 중에서도 필두에 둘 수 있는 것이 「TBDR에서 반투명(및 투명) 오브젝트의 렌더링이 늦어지는 것은 어째서인가」하는 점이다.

「이것은 받아들이는 방법의 문제라고 생각한다(웃음). TBDR에서는 불투명 오브젝트(픽셀)에 관해서는 어떤 오브젝트끼리 겹쳐져도 TBDR의 은혜로 각 픽셀은 1회밖에 묘화되지 않으므로, 픽셀 음영처리(픽셀 셰이딩)은 한번만 하면 된다. 따라서 퍼포먼스는 고속이며 안정적이다. 한편, 복수의 반투명 오브젝트가 걸린 묘화의 경우, TBDR에서는 거기에 관련된 모든 픽셀의 음영처리가 쌓여, 셰이더 유닛측에서는 그것을 1회씩 처리해야 하게 된다. 결국, TBDR의 은혜를 얻을 수 없다는 것이다.」(Beets 씨)

즉, 「TBDR에서는 불투명 오브젝트 묘화에 있어서 엄청난 퍼포먼스를 얻을 수 있지」만, 「불투명 오브젝트는 TBDR의 은혜를 얻을 수 없어」서, 그 격차로 인해 이것이  「느려진다」는 인상을 주게된다……고 말하고 싶은 듯 하다.

작년의 「니시카와 젠지의 3D 게임 팬을 위한 차세대 PSP-GPU 강좌」의 마지막 부분에서 「(3)묘화순서를 신경쓰지 않아도 올바르게 반투명묘화가 처리된다」고 한 기술에 대해, 「그건 아니지 않나?」라는 질문을 받았기에, 이에 관한 질문도 던져보았다.

「반투명 오브젝트가 걸려있어도 TBDR은 제대로 처리되며 "묘화는 일반적인 렌더링 파이프라인과 같은 방법으로" 처리될 뿐이다. 반투명 오브젝트의 경우에는 깊이의 전후에 관계없이 배제되지 않으며, 눈에 보이는 오브젝트이므로, 물리적으로 올바른 반투명 묘화를 하고 싶다면 뒤쪽에서 앞으로 미리 정렬해둬야 한다.」(Beets 씨)

실제 문제점으로서, 반투명 오브젝트가 있는 장면에서는 어떠한 묘화가 적합할까.

「TBDR에서는, 반투명 오브젝트의 묘화는 불투명 오브젝트의 묘화와 동시에 처리하기보다는 명시적으로 나누어서 처리하는 편이 효율이 좋다. 구체적으로는 먼저 불투명 오브젝트를 렌더링하고 그 후에 반투명 오브젝트를 렌더링해서, 나중에 양쪽을 합성하는 수법이다. 반투명 오브젝트의 묘화에서는 뒷방향 폴리곤의 컬링이 필요없고, 깊이 정보의 전후 관계에 기초한 컬링도 의미가 없기에 불필요하기 때문이다.」(Beets 씨)

또 하나 많았던 질문이 「Z버퍼를 사용하지 않는 TBDR에서 장면의 심도정보를 샘플링하여 처리하는 SSAO(Screen Space Ambient Occlusion)같은 포스트 이펙트를 처리할 수 있는가」하는 것이다.

「렌더링 옵션에서 심도값을 출력하도록 설정하면 Z 버퍼를 얻을 수 있으므로 문제없다. 알고리즘에 따라서는, 예를 들자면 MMRT(멀티 렌더 타겟)을 이용하여 특정 버퍼에 대한 선형적인 심도값을 얻는다는 방법도 있을 것이다.」(Beets 씨)

NGP의 SGX543MP4+ 보다도 신세대의 PowerVR 6 시리즈를 발표한 Imagination Technologies

NGP에 채용된 PowerVR SGX543MP4+은 하이엔드인 Power VR SGX5XT 시리즈로 분류되는 물건이지만, 실은 이 하이엔드 시리즈의 후계가 빨리도 등장한다는 것이 밝혀졌다.

PS3에 NVIDIA의 GeForce 7800 GTX에 상당하는 코어가 채용되는 것이 발표된 후에, NVIDIA 스스로가 프로그래머블 셰이더 ㅔ대를 1세대 새롭게 한 GeForce 8800 GTX 시리즈가 발표된 것을 떠올리게 하지만, 진화가 빠른 반도체 비즈니스에서는 피할 수 없는 사태이기도 하다.

이 신 PowerVR의 코드네임은 「Rogue」라 하며, PowerVR 6 시리즈에가 될 것이라고 발표되었다.

이 PowerVR 6 시리즈는 어떤 물건이 될 것인가.

「실은 자세한 내용은 홍보전략상 당분간은 감추기로 했다(웃음). 우리 고객중 하나인 ST ERICSSON이 발표한 것이 현 상황에서 이야기 할 수 있는 것이 전부라고 생각해주길 바란다. 진화가 현저한 이 분야에 있어서, 경합중인 타 회사를 자극하는 것은 가능한 피하고 싶다(웃음). 다만, 이미 몇몇 회사가 6시리즈에 관한 계약을 맺었고, 문의도 많은 것은 사실이다.」(Harold 씨)

ST ERICSSON의 뉴스 릴리즈는 이쪽에서 읽을 수 있다.

이에 따르면 선대 PowerVR 5 시리즈에 비해 20배의 렌더링 퍼포먼스를 발휘할 수 있으며, 그 렌더링 성능은 초당 3억 5천만 폴리곤, 130억 픽셀의 필레이트라고 한다.

NGP에 채용된 SGX543MP4(+)는 초당 1억 3300만 폴리곤, 초당 40억 픽셀이라는 것을 생각하면 상당히 높은 성능이라는 것을 예측할 수 있다.

또, PowerVR 6 시리즈의 연산성능은 210GFLOPS라는 것을 발표했다. 210GFLOPS라는 것은, 모바일 PC용 GPU로 치면 GeForce GT 430나 RADEON 6450 등과 같은 정도의 성능이라는 것이 된다.

이것은 상당히 만만치 않은 퍼포먼스다.

「Rogue는 OpenGL ES 2.0의 차세대판, 코드네임 「Halti」를 지원하는 것은 확실하다. 그와 함께 DirectX 11도 지원한다. 이보다 자세한 것은 말할 수 없다.」(Harold 씨)

DirectX11의 지원……이것은 다시 말해 Rogue에서는 테셀레이션 스테이지의 탑재를 시사하고 있다는 말이다.

만에 하나, NGP가 PowerVR 6 시리즈를 채용했다고 한다면 DirectX 9 세대의 셰이더 아키텍처를 채용한 PS3 보다도 선진적인 그래픽 아키텍처를 채용하게 되었을테지만, 그것은 이루어지지 않았다.

또, 이 “내기 아까운” PowerVR 6 시리즈는 실제로는 2011년 내의 제공이 예정되어 있다. PowerVR을 갖고 있는 Imagination Technologies의 약진은 2011년에도 멈출줄을 모른다.

원문

지금와서 묻기 힘든 NGP 스펙 강좌
그 스펙은 휴대용 게임기로서의 새로운 놀이를 추구하기 위한 것

GDC 세션에서도 닌텐도 vs 소니 컴퓨터 엔터테인먼트가 전개!?

GDC 3일째는 닌텐도의 이와타 사토루 씨의 기조연설로 막을 열었다.

기본적으로는 북미에서 발매를 앞둔 「닌텐도 3DS」에 화제의 촛점을 맞춰, 시종일관 그 신기능에 관한 해설과 북미 전용의 새로운 서비스의 소개를 한 것뿐으로, Apple의「iPad 2」의 발표회가 겨우 몇분이면 걸어갈 수 있는 장소에서 거의 동시간대에 보란듯이 열린 것을 생각하면, 펀치가 약해보인다.

다만, 세션의 최종반에 이와타 씨는 「다양화하는 게임 마켓 속에서, 게임 하드웨어와 게임 컨텐츠 양쪽의 제공자인 닌텐도의 입장에서 어떻게 할 것인가」에 대해 이야기했는데, 이중에 상당히 뜻깊은 발언이 있었다. 이에 관한 상세한 내용은 본지의 기조강연 레포트를 참조하기 바란다.

소니가 말하는 PlayStation Suite전략을 따라, 닌텐도도 타사의 플랫폼에의 컨텐츠 제공이나, 닌텐도 하드웨어의 독립 개발자의 참가를 허용해갈지? 2011년은 전년도 이상으로 업계의 동향에 주목할 필요가 있을 것 같다.

그건 그렇고, GDC 3일째인 오늘은 참가자들에게 있어 「괴로운 사상검증」을 강요받는 날이었다.

그것은 오후 1시 30분부터의 프로그램으로, 3DS 개발비화에 해당하는 「Development Process of Nintendo 3DS」과, 소니 컴퓨터 엔터테인먼트의 NGP의 기술 세션 「Next Generation Portable Entertainment System」이 경합하였기 때문이다.

업자에게 있어서는 괴로운 결단이었겠지만, 본 기사에서는 NGP 세션 쪽을 커버하기로 했다.

유기 EL 패널은 NGP에 있어 가장 "고집"이 보이는 부분

세션에서는 먼저 NPC의 기본 스펙을 총점검하였다.

NGP의 화면 사이즈는 5.0인치이며, 현행 PSP는 4.3인치. 면적비로는 NGP 쪽이 약 35% 넓다. 해상도는 PSP의 480x272 픽셀에 대하여 NGP는 960x544 도트로 4배의 해상도가 된다. 풀 HD의 1920x1080 픽셀의 약 1/4에 상당하여, 말하자면 QHD(쿼터 HD)라는 느낌으로 부를수 있지 않을까. 그리고 영상 패널로 유기 EL이 채용되었다는 점이 NGP의 가장 주목받는 특징이다.

결론부터 이야기하자면, NGP는 지금까지의 소니제 게임기의 최대성능중시 설계와는 달리, 상당히 비용을 중시하여 설계된 감이 있다. 현 PSP에서는 사치스럽게도 커스텀 설계의 프로세서를 채용했었고, 광학 드라이브(UMD)도 마찬가지로 커스텀 설계(기반 기술은 DVD)였지만, NGP의 CPU와 GPU는 말하자면 "있는 것"을 짜맞춘 것으로, 비용이 들어가는 광학 드라이브는 폐지되고, 얼핏 비용이 많이 들어갔을 것 같은 센서류는 휴대폰 등에서 넓게 이용되고 있는 범용 MEMS(Micro Electro Mechanical Systems) 부품으로 대단한 것은 아니다.

이에 반해 이 고해상도 하이 픽셀피치의 유기 EL 패널은 범용품이 아닌, NGP를 위해 제공된 것이라고 보여진다. 물론 「소니 자사제니까」라는 변명도 할 수 있겠지만 어쨌거나 「굳이 유기 EL을 채용한다」는 것 만큼 NGP에서 고집을 부린 부분이라고 할 수 있다.

참고로 유기 EL 패널이란, 간단히 말하자면 각 화소가 유기물 LED(영어 표기로는 OLED)로 되어 있는 자체발광 영상 패널이다. 검은색은 화소가 완전히 꺼져있어 컨트라스트감이 양호하며, 화소의 켜짐・꺼짐 응답속도는 나노초 수준으로 밀리초 수준의 액정과는 동화 성능이 선을 달리한다고 할 수 있다.

여담이지만, 2007년 소니에서 20만엔에 발매된 11인치 사이즈의 유기 EL TV 「XEL-1」은 이 NGP와 거의 같은 해상도였다.

NGP의 CPU는 대칭형 멀티코어 CPU

CPU는 ARM의 CORTEX A9(ARM9)를 채용했다.

현재 클럭에 관한 것은 미확정이지만, 쿼드(4) 코어 사양이 되어있다는 것은 확정되어있다.

ARM9는 분기예측기가 있는 숏 파이프라인 사양의 32비트 아키텍처 CPU다. 쿼드코어판이지만 각 코어의 명령 캐시, 데이터 캐시는 코히어런시(주:캐시 메모리와 메인메모리의 내용을 일치시켜 부적합성을 배제하는 것)가 유지된다. 즉, 각 코어가 병렬로 동작하고 있어도, 메모리 내용의 일관성에 관해서는 프로그램 측에서 신경쓸 필요가 없는 것이다.

ARM9는 부동소수점 유닛 및 SIMD 유닛을 옵션으로 취급하지만, NGP에 채용되어 있는 것은 이것이 모두 실장되었다. 현행 PSP는 MIPS R4000계 커스텀 CPU의 싱글코어였지만, NGP는 멀티코어, 그것도 쿼드코어라는 것은 감개무량하다.

멀티코어 CPU를 탑재했다는 것 때문에 플레이스테이션3와 비교되는 일이 많은 NGP이지만, PS3의 CPU인 CELL 프로세서는 지휘자격인 PPU 단일 코어와 8코어(중 1코어가 무효화, 다른 1코어는 시스템이 점유, 게임용으로는 6코어가 해방되어있는 사양)의 128비트 SIMD형 벡터 RISC 프로세서인 SPE로 이루어진 비대칭형(이종혼합형) 멀티코어 CPU이므로, 사양적으로도 스펙상으로도 전혀 다르다고 할 수 있다.

대칭형 멀티코어 CPU라는 의미에서 NGP의 CPU는 Xbox 360의 CPU에 가깝다. 이 점은 David Coombes 씨도 같은 말을 했다. 참고로 NGP에서는 4코어의 ARM9 중 1코어가 시스템(OS)에 의해 점유되어 있으므로, 게임용으로는 3코어가 해방되어 있는 것이 된다.

메모리 용량은 PSP의 32MB에 비해 대폭으로 증량되었다고 어필했지만, 그 용량은 현시점에서는 비공개 상태이다.

또, 세션에서 Coombes 씨는 「PS3의 용량에 가까운 이미지」라는 힌트를 암시했다. 액면대로 받아들이자면 256MB가 된다. 다만, 「현재의 프로토타입판 개발판 NGP에서는 512MB의 용량이 있지만, 현재 그 절반을 시스템이 점유하고 있다」는 정보도 들려오므로, 그런 의미에서 512MB÷2=256MB라는 수치를 들고 있는 것일지도 모른다. 최종적인 사양은 아직 모르지만, Coombes 씨는 「요즘 게임을 실행하는데 부족함이 없는 용량」이라고 이야기했다.

NGP의 GPU의 포텐셜~셰이더 세대는 PS3의 GPU와 동세대지만 퍼포먼스는 차이가 있다는 것을 인정

GPU에는 Imagination Technologies의 PowerVR계열「SGX543MP4+」가 채용되었다. 이 GPU에 관해서는 작년의 본 연재 「니시카와 젠지의 3D 게임 팬을 위한 차세대 PSP-GPU강좌」에서 비교적 자세하게 해설하였으므로, 자세한 것은 그쪽을 참조하기 바라지만, 여기에서도 간단히 해설하도록 하겠다.

NGP에 채용된 SGX543 계열 GPU는 iPhone 등에 채용된 현행 PowerVR 계열 GPU의 하이엔드 모델에 해당하는 물건이다. NGP에 탑재된 것은 SGX543의 쿼드(4)코어 모델로, 렌더링 부하에 따라 구동되는 코어 수가 1~4 사이에서 변동된다. 그렇다고는 해도 게임을 동작시켰을 때에는 대부분의 경우에서 4코어가 구동되겠지만, 2D 응용 프로그램등이 동작할 때에는 동작 코어가 4코어 미만이 되게 될지도 모른다.

PowerVR 계열이라고 하면 그 렌더링 파이프라인이 TBDR(Tile Based Deferred Rendering) 아키텍처 베이스가 되지만, 이 TBDR 알고리즘에 관해서는 앞에서 이야기한 작년의 기사를 참조하기 바란다.

다만, 셰이더 아키텍처로서는 OpenGL ES 2.0에 준거했으므로, 이것은 DirectX 세대로 말하면 DirectX 9, 프로그래머블 셰이더 3.0 사양(SM3.0) 세대가 되어, PS3와 거의 동세대라는 것이 된다.

이 부분만 떼내어 「NGP에서 PS3의 소프트가 움직인다」라는 풍설이 돌게 된 것 같은데, 실제로는 「동세대의 셰이더를 움직일 수 있다」고 하는 것이 올바르다.

비디오 메모리 용량은 현행 PSP는 2MB였지만, NGP에서는 비 프로그래머블 셰이더 세대인 현행 PSP와는 달리 비디오 메모리가 다양한 버퍼나 데이터 저장 목적으로 이욛되는 만큼 대폭으로 증량되었다.

필레이트 성능만으로 비교하자면 현행 PSP는 6억6천만 텍셀 정도, NGP는 대충 잡아 적어도 40억 텍셀 정도로 약 6배 정도가 향상된 것으로 보이지만, 실은 NGP의 화면 해상도가 현 PSP의 4배로 높아졌기 때문에, 실제로는 그 정도의 여유가 없을지도 모른다.

이렇게 과도로 높아진 「NGP의 그래픽 표현은 PS3 그래픽스 상당」한다는 속설에 대해, Coombes 씨도 「NGP는 휴대용 기기이며, 퍼포먼스와 마찬가지로 배터리 시간을 중요시하고 있다. 그러므로 NGP의 퍼포먼스가 PS3와 동등하지는 않다」고 발언했다.

또, PS3의 리소스(3D 모델이나 셰이더)를 그대로 가져오면 확실하게 퍼포먼스가 떨어지므로, NGP에 적합하게 스케일 다운할 필요가 있다는 것도 지적되었다.

PSP에서 진화, 개량된 NGP의 입력장치군

필자가 개인적으로 PSP와 비교하여 가장 강화되었다고 생각하고 있는 점이 입력 장치 부분이다.

PSP에 채용되어있던 PS 패밀리 전동의 디지털 패드와 ○, ×, △, □ 버튼은 그대로 계승되고, 아날로그 스틱부분은 종래의 슬라이드 패드 방식에서 리얼스틱으로 변경되었다.

등단한 Coombes 씨도 「2D 아날로그 패드가 아닌, 3D 아날로그 패드다」라는 점을 강조했다.

앞에서 이야기한 유기 EL 화면은 정전용량식의 멀티터치 입력에 대응하지만, 그 입력해상도(정밀도)는 상당히 높다고 주장했다.

특징이라고 할 수 있는 배면 터치패널은, 화면을 뒷쪽에서 터치입력시키는 특이한 것으로, 이것도 멀티터치에 대응한다. 배면 터치패드의 입력 에리어는 화면 사이즈에 준하고 있으므로, 표시화면을 뒤에서 만지는 감각으로 입력을 할 수 있을 것 같다.

Coombes 씨는 「배면 터치패드는 터치하고 있는 손가락이 영상을 가리지 않으므로, 게임 조작에는 최적의 터치 입력방법이다」라고 어필했다.

6축 모션 센서는 3축 가속도 센서와 3축 자이로스코프를 통한 것으로(「SIXAXIS」기능), PS3의 표준 컨트롤러인 DUALSHOCK 3에 준하는 스펙이 되어있다.

이 외에, 3축 전자 컴파스가 내장되어 있어 본체를 어떻게 기울여도 지구상에서의 동서남북을 알수 있게 되어 있다. 이 부분은 DUALSHOCK 3에는 없는 NGP의 독특한 센싱 기능이라고 할 수 있다.

이미지 센서로서 카메라가 본체의 앞뒤면 양쪽에 붙어 있으며, 게임 이용을 배려하여 고감도 및 60fps 촬영이 가능한 것으로 했다고 한다.

게임 카트리지의 용량은 2GB,4GB의 2종류~세이브 데이터 등을 게임 카트리지에 보존하는 것도 가능

일반판매 소프트웨어는 카트리지(게임카드)로 공급되며, 그 용량은 2GB와 4GB의 2종류가 존재한다는 것이 발표되었다.

카트리지는 기본적으로 ROM 카트리지가 되지만, 전체용량의 5~10%에 쓰기 가능한 용량이 할당되는 사양이 되어있다. 이것은 세이브 데이터를 보존하거나, 혹은 발매후에 제공되는 업데이트나 버그 수정 패치 등을 저장하기 위한 목적으로 이용된다.

이 외에 외부 미디어로서 시판 중인 메모리카드를 이용할 수 있다는 것도 밝혀졌다. SD 카드인지 메모리 스틱인지 메모리카드의 종류는 밝혀지지 않았지만, ROM 카트리지보다도 대용량인 것까지 지원되며, 여기에는 온라인으로 구입한 게임이나 다운로드한 영화나 음악 등의 멀티미디어 파일이 저장된다고 한다.

통신기능으로서 무선 LAN(Wi-Fi)과 3G 휴대폰 통신망을 이용할 수 있게 되어있으며, Wi-Fi+3G 대응 모델과 WiFi 온리 모델의 2종류가 계획되어 있다. 대응하는 Wi-Fi 종류는 IEEE 802.11b/g/n이 확정되어 있지만, 3G 네트워크에 관한 상세한 사양은 미정이다.

위치검출기능으로는 GPS를 이용할 수 있지만, Wi-Fi망을 이용하여 위치 검출 서비스 등을 이용하는 것도 가능하다고 한다. 이런 기능은 GPS 위성이 잡기 힘든 지하 거리나 실내등에서의 위치 검출에 효력을 발휘하게 될 것이다. 또한, GPS 기능은 3G 대응 모델과 세트로 제공된다고 한다(Wi-Fi 온리 모델에는 GPS 기능이 없음).

NGP의 개발킷은 Visual Studio 베이스

이번 세션에서는 개발환경에 관한 정보도 있었다.

현행 PSP의 개발킷에서는 제어용의 외부 박스와 PSP 커맨더 양쪽을 이용해야 했지만, NGP의 개발환경은 자기완결형의 시스템이 되었다. 즉, 개발자용 NGP는 단독으로 개발도중판 소프트의 동작확인이나 테스트 플레이를 할 수 있게 되어있다. 앞에서 이야기한 터치패널/터치패드, 각종 센서류같은 다채로운 입력장치나 GPS, WiFi, 3G 등의 서비스군등을 조합한 실천적인 테스트를 단독으로 할 수 있다는 것이다. 개발자용 NGP는 메인메모리 용량등은 시판용 NGP보다도 큰 듯 하지만, 단독으로 NGP로서 동작할 수 있는 포텐셜을 갖고 있다는 것이다.

또, 개발킷은 Windows 베이스의 PC로 제공되며, 게다가 커스텀 사양의 Visual Studio IDE를 이용할 수 있다. 지금까지의 LINUX 베이스의 개발환경과는 다른 Windows PC 베이스의 개발환경이 되었으므로, 종래의 소니 플랫폼과 비해 멀티플랫폼 지향 타이틀을 개발하기 쉬워졌다.

또한, CPU, GPU, MEMORY의 병목 분석을 도와주는 오리지널 퍼포먼스 튜닝 툴도 함께 제공된다고 한다. 이러한 적극적인 사양정보개시와 개발환경의 개선의 움직임도 있어, 다양한 미들웨어 메이커가 NGP 지원을 표명하고 있다.

개발환경의 정비상황이나 미들웨어 지원의 충실도라는 면에서 휴대게임기라기보다는 PS3, Xbox 360 등의 거치형 게임기에 가까워진 만큼, PS3, Xbox 360 대응 타이틀의 NGP 용으로의 멀티플랫폼 전개도 충분히 가능할 것이다.

단, 앞에서 말한 대로 아무래도 성능차가 있는 만큼, PS3나 Xbox 360 용의 빅 타이틀 용의 어셋(3D 모델이나 셰이더)를 전용하면서도 3D 모델을 간략화하거나, 셰이더를 줄이거나……하는 NGP 용의 스케일 다운적인 튜닝은 필요하다.

NGP 용 최신 데모가 공개되다~증강현실(AR) 대응 게임의 등장을 시사

세션 중에는 NGP용 게임의 가능성을 시사하기 위한 테크니컬 데모가 3개 정도 공개되었다.

하나는 배면 터치와 SIXAXIS 기능을 활용한 「마블 매드니스」같은 구슬 굴리기 액션게임이다.

구슬은 NGP 본제를 움직이거나 기울임으로서 굴릴 방향을 바꿔, 플레이어는 마치 게임 세계에 대하여 물리적으로 간섭하고 있는 것같은 실감을 느낄 수 있다. 또, 정면화면에서의 터치가 아니라, 배면 터치를 통한 구슬에의 간섭은, 손가락이 게임 화면을 가리지 않아서 직관적이라는 것 이상으로 조작하기 쉽다는 메리트가 있다.

또 하나는 「언차티드」의 장면을 NGP로 포팅한 테크니컬 데모로, 이쪽은 PS3용의 같은 빅 타이틀, 시리어스 타이틀을 NGP에 가져올 때의 가능성을 보여주기 위한 것이다.

이 데모에서는, 보통 아날로그 스틱 조작이나 버튼 조작에 의한 PS3스러운 게임 플레이를 체험할 수 있지만, 화면 내의 위치 지정이나 격투전 등의 요소요소에 있어서는 터치로 조작을 할 수 있게 했다.

아날로그 스틱이나 버튼은 적확한 게임 내 조작을 하기에 가장 좋은 선택이며, 그에 반해 터치 조작은 공간적인 지정이나 제스처 입력을 직시적으로 할 수 있다는 이점이 있다.

터치 뿐만이 아니고, 스틱과 버튼만이 아닌, 놀게 하기 위한 게임마다 유저에게 적재적소에 맞는 인터페이스를 사용케 하는 것이 NGP의 새로운 게임 체험인 것이다.

마지막 데모는 증강현실(AR:Augmented Reality)의 데모로, NGP의 카메라 기능과 SIXAXIS 기능을 활용한 것이었다.

일반적인 AR에서는 QR 코드(바코드)같은 인공 마커(태그)로 위치정보를 인식시키거나, 장면의 지오메트리 정보를 파악하거나 하지만, 이 데모에서는 현실세계에 있는 것 "그 자체"를 마커(태그)로 이용하여 위치나 지오메트리를 파악할 수 있게 되어 있었다. 이것을 소니는 「내추럴 마커 테크놀로지」라고 호칭하고 있었는데, 실제로는 뭐든 태그나 마커로 이용할 수 있는 게 아니라, 미리 형상정보와 텍스처를 시스템 측에서 사전에 등록해둘 필요가 있다.

데모에서는 PS3 소프트 「사루겟츄」의 패키지 위에서 놀고 있는 삐뽀사루를 NGP 시계의 영상에 출현시키거나, 바닥에 놓아둔 공룡의 일러스트 포스터로부터 NGP 시계의 영상에 공룡을 출현시키거나 했다.

삐뽀사루는 아주 작아서 삐뽀사루 전체가 NGP에 비쳐졌지만, 공룡은 인체의 수배는 되는 거대한 물체라, NGP를 위쪽으로 들어올려 NGP를 보면 아래쪽에서 올려다본 공룡의 몸의 일부가 비쳐지게 된다. 그대로 NGP를 갖고 이동하면, 거대한 공룡을 그 위치에서 본 시계가 NGP에 비쳐진다.

이것은 현실세계의 지오메트리에 적합하게 구축된 가상 공간에 거대한 공룡을 출현시키고, 이것을 NGP에서 적절한 현실세계의 풍경에 합성하여 NGP에 표시함으로써 실현한다. 더욱 구체적으로 말하자면, 바닥 위의 공룡 포스터를 놓은 후, 유저가 NGP를 어느 정도나 이동시켰는가, 방향을 바꿨는가……등을 NGP 내장 SIXAXIS를 활용하여 산출하고, 이 정보를 통해 현실세계에 대한 카메라 벡터를 구하고, 이 카메라 벡터를 현실세계와 매칭되어 있는 가상 공산상의 공룡 CG를 렌더링한 것이다.

그야말로, NGP의 기능을 풀활용한 테크놀로지 데모라고 할 수 있다.

현행 PSP에서는 확실히 하이스펙 게임을 휴대 게임기에서 플레이한다는 것을 메인테마로 한 감이 있었지만, NGP에서는 오히려 이러한 새로운 놀이가 가능한 플랫폼으로서 키워간다는 사상을 느낀다.

+ Recent posts