[JumpToDX11-11] DirectCompute 를 위한 한걸음!

DirectX 11 2010. 2. 11. 09:00 Posted by 알 수 없는 사용자


앞선 시간을 통해서 GPGPU 를 위해서 마이크로소프트가 제공하는 플랫폼이
DirectCompute 라는 것이라고 말씀드렸습니다.
앞으로 DirectX11 을 지원하는 모든 그래픽카드들은 이 DirectCompute 를 지원할 것입니다.
그 이외에도 일부 DirectX10 을 지원하는 그래픽카드들도 지원을 하고 있습니다.


GPGPU 를 위해서 가장 기본적이고 핵심이 되는 기능은 무엇일까요?
저는 GPU 에서 처리된 메모리를 CPU 쪽의 메모리로 보내는 것이라고 생각합니다.
( 이는 개인 의견입니다.^^ )
즉, 그래픽카드에 있는 메모리를 메인메모리로 보내는 작업입니다.
DirectX9 세대까지는 이 작업이 불가능 했습니다.
예를 들면, 그래픽스 파이프라인 중간에 처리된 결과를 다시 가공할 수 있는 방법은
VertexShader 나 PixelShader 같은 쉐이더 스테이지 정도 뿐이였습니다.

하지만 DirectX10 부터는 이들에 대한 중간 결과를 메인메모리로 보내는 기능이 추가되어지면서,
GPGPU 의 시작을 알렸다고 생각합니다.
이 단순한 Copy 작업이 앞으로도 얼마나 유용하게 사용될 수 있을지는 기대가 상당합니다.



< DirectCompute 를 위한 ComputeShader >

DirectCompute 를 위해서 개발자가 할 일은 ComputeShader 를 작성하는 일입니다.
ComputeShader 는 HLSL 이라는 기존 DirectX 의 쉐이더 문법 구조로 작성을 합니다.




HLSL 코드는 DirectX 쉐이더 컴파일러인 FXC 나 API 를 통해서 컴파일 됩니다.
HLSL 은 결국 최적화된 IL 코드를 생성하게 되고,
이 IL 코드를 기반으로 런타임에 각각의 하드웨어에 최적화된 명령어들로 변환
되어져서 실행됩니다.


< GPGPU 에게 실행이란? >

GPGPU 를 활용해서 실행한다는 것은 하드웨어 내부적으로 어떻게 동작하도록 할까요?
앞선 시간에 GPU 는 병렬 처리에 최적화된 많은 SIMD 형태로 구성되어져 있다고 언급했었습니다.
결국 이들은 스레드들의 그룹으로써 실행합니다.
스레드들을 얼마나 많이 생성할 것인지를 개발자가 정해주면, 그에 맞게 연산을 수행합니다.

API 에서는 이들을 큰 그룹으로 나누어 줍니다.
큰 그룹으로 나누어 주는 API 는 ID3D11DeviceContext::Dispatch() 입니다.

ipImmediateContextPtr->Dispatch( 3, 2, 1 );

이렇게 큰 블럭 단위로 나누고 난 후에
ComputeShader HLSL 에서는 이들을 세부적인 스레들로 분할하는 문법을 지정합니다.

[numthreads(4, 4, 1)]
void MainCS( ... )
{
        ....
}




결과적으로 위의 그림처럼 스레드들이 생성되어서 병렬적으로 실행이 됩니다.
위에 나열된 숫자들은 스레드 ID 로써의 역활을 합니다.
즉, 어떤 스레드의 ID 가 MainCS 함수에 파라메터로 넘오오면,
그 ID 를 통해서 해당 버퍼에 값을 작성하게 됩니다.

아래에 간단한 예가 있습니다. 

[numthreads( 256,1,1) ]

void VectorAdd( uint3 id: SV_DispatchThreadID )
{

  gBufOut[id] = gBuf1[id] + gBuf2[id];

}


아무리 스레드들이 복잡하게 동작하더라도, 위와 같이 ID 를 통해서 제어한다면
그 어떤 작업도 문제없이 할 수 있습니다.

일단 먼저 어떻게 DirectCompute 가 실행되어지는지에 대해서 살펴보았습니다.
실행까지 가기 위해서는 일련의 절차를 거쳐야 합니다.
이들에 대해서는 앞으로 차근차근 살펴보겠습니다.



참고 자료
http://microsoftpdc.com/Sessions/P09-16
본 내용은 위의 PDC 를 참고해서 만들었습니다.

[JumpToDX11-2]DeviceContext...넌 누구냣!!

DirectX 11 2009. 8. 24. 14:00 Posted by 알 수 없는 사용자



지난 회에서 DXGI 에 대해서 잠깐 살펴보았습니다.
DXGI 에 대한 사용방법은 여기서 언급하지 않습니다.
왜냐하면 제가 진행할 코딩에서는 기본적으로 셋팅되어 있는 그래픽 카드를 사용하는 것을 전제로
진행할 것이기 때문입니다.

혹시 호기심이 더 왕성하신 분들은 IDXGIFactory 인터페이스를 살펴보시면 됩니다.
멤버 함수중에 MakeWindowAssociation, EnumAdapters 정도 살펴보시면 도움이 될 것입니다.
( API 함수 이름만 봐도 느낌이 팍팍! )

예상하시겠지만, DXGI는 연결가능한 장치(어댑터)들을 나열해서
그것 중에 하나 선택하는 역활이 필요합니다.
저는 기본적으로 설정된 어댑터를 사용할 것이기 때문에 이들에 대해서는 언급하지 않겠습니다.
 DXGI 계열의 API들도 양이 상당합니다.( 그래서 일단 패스~ )


지난 회에 언급했던 디바이스 초기화를 위한 변수들 기억하시나요?
다시 나열해 보면 아래와 같습니다.




< IDXGISwapChain >

가장 먼저  IDXGISwapChain 에 대해서 살펴봐야하겠지만, 이것에 대한 별도의 설명이 필요할까요?
Front Buffer( 현재 화면에 보여지는 버퍼 )와 Back Buffer( 현재 연산을 해서 기록하는 버퍼 ) 를
준비해서 이것을 Flip 시키면서 번갈아 가면서 보여주는 것을 의미합니다.
( 너무 고전적인 내용이라 더 설명하면 혼날듯...)

우리가 렌더링할 영역(버퍼)에 대한 포맷과 같은 각종 속성들을 설정해 주어서 생성을 요구하고,
포인터를 받으면, 이들 버퍼에 대한 정보를 제어
할 수 있습니다.
나중에 살펴보게 되겠지만, Present() 라는 API 를 기억하시나요?
9.0 에서는 이것이 ID3DDevice9의 멤버함수로써 사용했었습니다.
하지만 현재는 IDXGISwapChain 의 멤버함수로 등록되어 잇습니다.
그래서 이에 대한 포인터가 필요합니다.^^
결론적으로 얘기 드리면 앞으로 화면 출력에 관한 모든 것은 IDXGI 계열의 인터페이스로서 제어할 수 있습니다.





아마 위와 같은 형식이겠죠? ( 각각의 성분에 대한 설명은 생략합니다...저걸 다 어찌 설명해요..-_- )

 

 

 < DeviceContext...넌 누구냣!! >

이상한 인터페이스가 DirectX11 에서 생겼습니다.
Device는 무엇인지 알겠는데, DeviceContext 는 또 무엇일까요?
사실 이것은 그동안 Device 인터페이스들이 해오던 역활을 두가지로 분리한 것에 지나지 않습니다.

즉, ID3D11Deivce 는 주로 리소스( 버퍼나 텍스쳐 등 )의 생성에 대한 인터페이스이며,
ID3D11DeviceContext 는  이들 리소스를 제어하고 관리하기 위한 인터페이스입니다.

그렇다면 왜 이렇게 두 가지로 분리된 것일까요?
먼저 아래의 그림을 살펴보겠습니다.




우리가 렌더링을 수행하기 위해서는 애플리케이션에서는 관련 Core API 와 Runtime을 사용하게 됩니다.
이들 Core API 와 Runtime 은 우리가 필요한 렌더링에 관한 모든 것을 수행합니다.
메모리 할당이나 리소스들의 수정, 메모리 바인딩, 각종 렌더링 스테이트의 제어 등등 굉장히 많죠.
( 물론 쉐이더 코드들을 통해서도 이들을 제어할 수 있는 부분이 있습니다만,
  여기서는 흐름상 고려하지는 않습니다.  ) 

DirectX 시스템은 Application 과의 오버헤드를 최소화 하기 위해서
이들 사이를 매우 얇은 추상화 단계로 디자인 했었습니다.
즉, Core API 나 Runtime 들은 바로 Driver 에 접근할 수 있었습니다.

그래도 약간(?) 존재해 있는 Application 과 하드웨어간의 오버헤드를 줄이기 위해서
기존의 Device 의 역활을 Device 와 DeviceContext 로 분리
하게 된 것입니다. 

그렇다면 여기서 발생되는 오버헤드란 것은 어떤 것일까요?( 의문에 의문 연속입니다..-_- )
우리가 사용하는 각종 API 들은 Runtime 에 전달되어서 하드웨어가 인식할 수 있는
커맨드( Command ) 들로 변환
됩니다.

Runtime 은 이들 커맨드들을 담을 수 있는 메모리 공간을 가지고 있어서, 커맨드들을 저장하게 됩니다.
그러다가 이들 버퍼가 가득차거나, 혹은 렌더링 데이터의 업데이트가 필요한 경우에
이들을 하드웨어로 전송하게 되는 것입니다.
바로 이 커맨드들에 대해서 오버헤드가 발생하는 것입니다.
이 커맨드들이 오버헤드를 발생시키는 이유는 여러가지가 있었습니다.
하드웨어의 경우에는 프로세싱( processing ) 스타일이 매우 다양하기도 했고,
API 와 하드웨어 상에서 커맨드 전달이 잘못 전달되는 경우도 있었다고 합니다.
( 아무래도 하드웨어가 너무 다양해서가 주된 이유였던 듯 합니다. )

이들에 대한 오버헤드를 줄이는 방법을 고민하던 중에 나온 결과물 중에 하나가
바로 'DeviceContext' 라는 것입니다.
( 뒤에 언급할 기회가 있겠지만, 'State Object' 가 바로 이 오버헤드를 줄이기 위해 등장한 개념이기도 합니다. )

Device 의 경우에는 오버헤드를 줄이기 위해 등장한 개념이
리소스의 생성/해제를 담당하는 커맨드들과 그 리소스들을 제어하는 커맨드들로 분리하는 것입니다.

 

분리함으로써 어떤 성능 향상이 있었을까요?
리소스의 생성과 해제는 사실 멀티스레드 형태의 API 호출에도 별 문제가 없습니다.
어차피 명령어들이 큐 형태로 쌓이게 될테니까요.
반면에 렌더링 커맨드들은 멀티스레드 형식으로 구성되면 큰일 나겠죠?

결국 Device 는 Free threaded 형식으로 구성되었고,
DeviceContext 는 그렇지 않다는 것
입니다.
Free threaded 형식으로 구성되었다는 것은 스레드에 안정성을 유지하기 위한
별도의 lock/unlock 작업이 필요없다는 것입니다.
멀티스레드에 안정적이라는 얘기는 스레드 세이프하다는 것입니다.

(정확하게 확신은 아직 드릴 수 없지만, 멀티스레드 관련 렌더링과도 관련이 있는 부분이 여기이지 않을까요.)

사실 리소스의 생성과 해제가 성능에 많은 부분을 차지한다고 볼때,
이렇게 분리되어진 것을 환영해야 할 것입니다.

 

 < 다음 회에는... >

글이 좀 길어지는 것 같아서 일단 여기서 마무리 합니다.
다음 회에는 나머지 초기화 부분에 대해서 계속 언급하겠습니다.^^

 





 

'DirectX 11' 카테고리의 다른 글

[DX11_#2]D3D Buffer( 2 / 2 )  (0) 2009.10.13
[DX11_#1]D3D Buffer( 1 / 2 )  (0) 2009.09.22
[JumpToDX11-4] ID3D11View  (0) 2009.09.07
[JumpToDX11-3] Feature Level  (0) 2009.08.31
[JumpToDX11-1] 사라진 Direct3D 오브젝트를 찾아서...  (8) 2009.08.17

[JumpToDX11-1] 사라진 Direct3D 오브젝트를 찾아서...

DirectX 11 2009. 8. 17. 14:00 Posted by 알 수 없는 사용자

< 인사 및 소개 >

안녕하세요.
저는 이번에 vsts2010 에 참여하게 된 조진현 이라고 합니다.

어떤 주제에 대해서 글을 쓰다는 것은 무척 어려운 일입니다.

그렇기 때문에, 이 스터디 참가를 굉장히 망설이기도 했습니다.
많은 분들과 함께 열정을 가지고 참가를 결심했고, 드디어 처음으로 글을 남기게 되었습니다.
제가 가장 우려하는 것은 잘못된 지식을 전달하는 것입니다.
그래서 조심스러운 마음으로 글을 작성할 것입니다.
잘못된 부분이나 미흡한 부분이 있으면, 바로 지적해주시면 감사하겠습니다.

제가 언급할 큰 주제는 DirectX 11 과 관련이 있습니다.
그 중에서도 멀티 코어를 활용한 DirectX 사용에 초점을 두고 글을 전개할 생각입니다.
글의 주요 대상은 DirectX9 를 사용하시다가 DirectX11 을 사용하고자 하시는 분들입니다.

일단 방대한 변화에 대해서 모두 나열하기는 힘듭니다.

그래서 간단히 제가 코딩을 하면서 필요했던 API 위주로 살펴보면서 변화를 언급하고자 합니다.
그런데 하나 문제가 있습니다.
현재 DirectX 11 은 하드웨어 가속이 지원되지 않습니다.
오직 REF 모드로만 작동을 합니다.
아마도 아직 정식으로 widnows 7 이 출시가 이루어지지 않아서 그런 듯 합니다.
이점, 꼭 주의하시기 바랍니다.
괜히 DirectX 11 예제 실행했다가, 실행 성능이 떨어진다고 컴퓨터를 부수는 행위는 자제해 주세요.^^


< 사라진 Direct3D 오브젝트를 찾아서... >

우리가 가장 먼저 접하게 되는 DirectX 의 API 는 CreateDevice() 일 것입니다.
사실 이전 버전까지는 CreateDevice() 에 대해서 별도로 언급할 내용이 없었을 것이지만,
늘(?) 그렇듯이 DirectX 의 변화를 설명해주는 API 가 바로 CreateDevice() 입니다.
일단 CreateDevice() 를 위한 관련 변수들부터 봐야겠죠?
 



잠깐!!
가장 먼저 헤더 파일들을 살펴보는게 순서이죠.

헤더는 다음과 같이 변경되었습니다.
굳이 헤더의 용도에 대해서 일일이 나열하지는 않았습니다.

// Direct3D11 includes
#include <dxgi.h>
#include <d3d11.h>
#include <d3dCompiler.h>
#include <d3dx11.h>
#include <dxerr.h>

 

라이브러리 링크는 아래의 것들을 해주시면 됩니다.

#pragma comment( lib, "dxguid.lib" )
#pragma comment( lib, "d3dcompiler.lib" )
#pragma comment( lib, "dxerr.lib" )
#pragma comment( lib, "dxgi.lib" )
#pragma comment( lib, "d3d11.lib" )
#pragma comment( lib, "d3dx11.lib" )




변수들을 나열해 보겠습니다.




 생소한 부분이 눈에 보이시나요?
 'ID3D11DeviceContext' 라는 것이 새롭게 등장했습니다. ( 다음 번에 언급할 것입니다. )
 그리고 Direct3D 인터페이스가 사라진 것을 찾으셨습니까?




위의 그림은 DirectX 9 의 아키텍쳐입니다.
우리가 작성하는 프로그램은 오직 Direct3D 나 GDI 를 통해서 저수준의 하드웨어와 통신을 할 수 있었습니다.

그런데 현재의 DirectX 아키텍쳐는 아래와 같습니다.



 여기서 또 하나 생소한 것이 등장했습니다.
바로 DXGI ( DirectX Graphics Infrastructure ) 입니다.
"DirectX9 에서 사라진 'Direct3D 오브젝트'를 'DXGI' 가 대체하는게 아닐까?" 라는 의문이 들었다면,
박수를 보내드리고 싶습니다.( 브라보~~ )


네, 맞습니다.
'DXGI' 라는 것이 바로 사라진 'Direct3D 오브젝트' 입니다.
'Direct3D 오브젝트' 의 역활에 대해서 혹시 기억하십니까?
하드웨어와 연결된 디바이스들을 나열하고, 모니터로 출력되는 결과들을 관리해주기도 했었습니다.
우리가 관리하기 힘든 저 수준의 작업들을 바로 이 'Direct3D 오브젝트'가 했었습니다.
그런데 이제는 이것을 'DXGI' 가 해주고 있습니다.
( IDXGISwapChain 보이시나요? 이것도 다음 회에 언급하겠습니다. )
 

아키텍쳐 구조를 보시면 아시겠지만, DirectX9 까지는 일반 애플리케이션에서 DirectX API 를 통하지 않고는
DirectX 를 사용할 수 없었습니다.
그런데 최근에는 일반 애플리케이션은 모두 DXGI 를 통해서 DirectX 를 사용하고 있습니다.
( 저만 놀라운 것은 아니겠죠? +_+ )
마이크로소프트에서도 강조하고 있는 사실 중에 하나가 바로 DirectX 는 더 이상 게임만을 위한 것이 아니라는 것입니다.
이제 사라진 줄 알았던 'Direct3D 오브젝트' 가 DXGI 라는 사실을 알았습니다.
앞으로 저수준의 작업이 필요하면 DXGI 를 직접 제어하거나 DirectX API 를 이용하셔도 됩니다.


< 다음 회에는... >

다음 번에는 실제로 DirectX API 를 이용한 초기화 작업에 대해서 다루고자 합니다.
즉, 우리가 앞서 선언했던 변수들에 대한 이야기를 하겠습니다.

'DirectX 11' 카테고리의 다른 글

[DX11_#2]D3D Buffer( 2 / 2 )  (0) 2009.10.13
[DX11_#1]D3D Buffer( 1 / 2 )  (0) 2009.09.22
[JumpToDX11-4] ID3D11View  (0) 2009.09.07
[JumpToDX11-3] Feature Level  (0) 2009.08.31
[JumpToDX11-2]DeviceContext...넌 누구냣!!  (1) 2009.08.24
일곱,여덟번째로 드디어 마지막입니다. ㅠㅠ

역시나 Q&A가 이어지고, 끝에 선물을 주네요.


그 동안 시청해주셔서 감사합니다. 조만간 새로운 내용으로 다시 돌아오겠습니다. ^^

p.s. 필요하다는 분이 계서서 이제까지의 자막 파일들 첨부합니다.


여섯번째입니다.

이미징 데모 설명과 시연을 끝내고 전체 요약 후 질답 세션으로 넘어갑니다.


혹 자막이 안보이시는 분은 유투브 플레이어에서 CC(Turn on Captions)를 활성화해주시면 보일겁니다.
(임베드 태그에서 기본으로 보이도록 설정했는데 왜 기본으로 안나오는지 모르겠군요;)
다섯번째입니다. 이제 끝이 보이네요;
많이 늦었죠? 죄송합니다. 출장 때문에 한 2주동안 바빴습니다.

이번 회에서는 Asynchronous Agents Library에 대해 더 자세히 살펴보고 실제 적용 예를 보여줍니다.


그 사이 VS2010 베타1의 발표와 함께 많을 자료들이 쏟아져 나왔는데요. AAL 관련해서도 유용한 글들이 보이더군요.



AAL로 액터 기반 병렬 프로그래밍을 경험해보세요! 
네번째입니다.

Combinable에 대해 자세히 다루고 PPL을 마무리한 뒤, Asynchronous Agents Library가 소개됩니다.


잘못된 번역이나 부족한 부분 있으면 알려주세요. ^^
세번째입니다.

관련 디버깅 유틸과 PPL 지원 알고리즘, 이미징 예제 병렬화, 동기화 개체자료구조 등이 소개됩니다.


잘못된 번역이나 부족한 부분 있으면 알려주세요. ^^
두번째 10분입니다.

자막 제작에는 Jubler를 사용하였습니다. 추천드립니다. :)

이젠 툴도 어느 정도 익숙해져서, 실제 10분 자막 제작에 드는 시간을 측정해보았습니다. 2시간반이 걸리더군요. ㅠㅠ 그냥 혼자 대충 듣고 이해할 때와는 달리 글로 정확하게 표현을 하려다보니 쉽지 않군요. 제가 빠삭하게 알고 있는 내용도 아니어서 더 시간이 걸린듯.

그래도 PPL이 태스크 개념 중심이라는 것, PPL과 TBB의 연동 계획 등 새로운 것들을 저도 알게 되어 기뻤습니다. 


언제가될지 모르겠으나 다음 회도 기대해주세요.
안녕하세요, 정재원이라고 합니다.

C++ 관련 글을 올리고 계신 흥배님과 마찬가지로 게임 개발자입니다.

그간 여러분들이 올려주시는 좋은 글들을 읽고만 있다가...; 무언가 올리지 않으면 짤리겠다는 위기감에 소재거리를 뒤져보았습니다;;

흥배님과 가능한한 겹치지 않는 주제와 방식으로 무엇이 적당할까 생각하던 중... 본 동영상을 발견하고는, 그래 여기에 자막을 달아보자! 생각하게 되었습니다. 작년 PDC에서 발표된 Parallel Pattern Library에 대한 동영상입니다.

왠지 간단할듯 여겨졌으나... 처음 해보는 자막 작업 쉽지 않더군요 ㅠㅠ 도구를 찾고 익히는데 시간이 더 들었습니다.

한시간이 넘는 것을 한번에 번역해 올리려면, 날새겠다는 생각이 들더군요; 유투브 업로드가 10분 미만의 동영상으로 제한된다는 것에 안도감(?)을 느꼈습니다...

이를 변명삼아 일단 10분 분량을 올립니다. 포스트 수를 늘리기 위한 수작 아니냐 라는 비난의 소리가 들립니다만... 맞습니다 ㅠㅠ 툴에 좀 더 익숙해지면 자주라도 올리겠습니다.

부족한 번역과 분량에 대해 건설적 충고 부탁드리고요, 기타 제 포스트에 제안 사항 있으시면 댓글 달아주십시오.