'DirectX 11 > Direct3d Mobile' 카테고리의 다른 글
| .NET 기반에서 공개소스 게임엔진 포팅하기 (0) | 2010/07/25 |
|---|---|
| [d3dm 기초] 1. wm6.x 개발환경 세팅 (4) | 2009/12/26 |
| .NET 기반에서 공개소스 게임엔진 포팅하기 (0) | 2010/07/25 |
|---|---|
| [d3dm 기초] 1. wm6.x 개발환경 세팅 (4) | 2009/12/26 |
| [JumpToDX11-14] DirectX9 세대의 테셀레이션( ID3DXPatchMesh 편 ) (0) | 2010/07/19 |
|---|---|
| [DX11_#5]DirectX11의 활용 사례(1/3) (4) | 2010/06/24 |
| [JumpToDX11-13] Tessellation 등장. (0) | 2010/06/15 |
| [JumpToDX11-12] DirectCompute 의 절차. (0) | 2010/04/26 |
| [JumpToDX11-11] DirectCompute 를 위한 한걸음! (0) | 2010/02/11 |
| [JumpToDX11-10] GPGPU 를 위한 DirectCompute. (2) | 2010/01/27 |
DirectX11의 여러가지 기능이 있지만 한눈에 무엇이 좋아졌는지 왜 써야 하는지에 대해서 의문을 가지시던 분들이 계실 것 같습니다.
Dirt2라는 게임에서 사용된 DX11의 기능을 보면 그런 의문이 조금은 사라질것 같습니다.
tessellation은 GPU파이프라인이 정점을 생성하는 것을 신속하고 능률적으로 계산하는 과정입니다.
Xbox360의 Xeons칩부터 ATI의 GPU까지도 존재하는 기능이나 HD 5000 시리즈에서 최초로 DX의 버젼이 지원되었습니다.
높은 bandwidth를 필요로하는 하이폴리곤 모델을 쓰지 않게 해주고, 특히 신속하게 현장의 풀잎 전체를 빨리 처리해야하는 상황에서도 유용한 기술입니다.
Dirt2에서는 저수치가 교차 할 때, 경기를 보고 있는 관중 그리고 트랙 바깥쪽에서 휘날리는 깃발에서 총 3개의 상황에서 사용을 하였습니다.
위 그림에서 본 것 처럼 tessellation은 더 상세한 모양을 추가해 더 현실적인 표현을 할 수 있습니다.
그러나 하이폴리곤 모델에서는 사용해선 안됩니다. 오히려 tessellation을 쓰지 않으니만 못한 경우가 생길 수 있습니다.
AMD에 따르면 " CPU는 차가 그것을 통과할 때 height field texture를 generates한다. tessellator는 카메라 위치에 근거를 둔 수 백 개의 삼각형을 생성한다.
그 결과로 아름답고, 물리적으로 정확한, 동적인 물 표면을 볼 수 있다. 게임의 DirectX 9에서의 surface는 다만 2개의 삼각형에 의해 나타낸 환영이다.”라고 했다.
물에 있는 여분의 잔물결 생성뿐만 아니라, 또한 바람에 휘날리고 있는 깃발에 있는 뒤틀림 및 잔물결을 더 추가하기 위해 사용 됩니다. Tessellation 은 또한 현실적으로 보이는 곡선을 창조하고, 이 기술은 low polygon군중을 더 디테일하게 보여주는데 사용되었습니다.
아래의 동영상을 보시면 확실하게 차이를 느끼실 수 있습니다.
| [JumpToDX11-14] DirectX9 세대의 테셀레이션( ID3DXPatchMesh 편 ) (0) | 2010/07/19 |
|---|---|
| [DX11_#5]DirectX11의 활용 사례(1/3) (4) | 2010/06/24 |
| [JumpToDX11-13] Tessellation 등장. (0) | 2010/06/15 |
| [JumpToDX11-12] DirectCompute 의 절차. (0) | 2010/04/26 |
| [JumpToDX11-11] DirectCompute 를 위한 한걸음! (0) | 2010/02/11 |
| [JumpToDX11-10] GPGPU 를 위한 DirectCompute. (2) | 2010/01/27 |
| [JumpToDX11-14] DirectX9 세대의 테셀레이션( ID3DXPatchMesh 편 ) (0) | 2010/07/19 |
|---|---|
| [DX11_#5]DirectX11의 활용 사례(1/3) (4) | 2010/06/24 |
| [JumpToDX11-13] Tessellation 등장. (0) | 2010/06/15 |
| [JumpToDX11-12] DirectCompute 의 절차. (0) | 2010/04/26 |
| [JumpToDX11-11] DirectCompute 를 위한 한걸음! (0) | 2010/02/11 |
| [JumpToDX11-10] GPGPU 를 위한 DirectCompute. (2) | 2010/01/27 |
앞선 시간에서 우리는 GPGPU 의 실행에 대한 간단한 개념에 살펴보았습니다.
이제 실제적으로 GPGPU 를 활용하는 절차를 살펴볼 차례입니다.
큰 절차는 다음과 같습니다.
< DirectCompute 의 초기화 >
가장 먼저 DirectCompute 를 초기화 해야 합니다.
hr = D3D11CreateDevice
(
NULL, // default gfx adapter
D3D_DRIVER_TYPE_HARDWARE, // use hw
NULL, // not sw rasterizer
uCreationFlags, // Debug, Threaded, etc.
NULL, // feature levels
0, // size of above
D3D11_SDK_VERSION, // SDK version
ppDeviceOut, // D3D Device
&FeatureLevelOut, // of actual device
ppContextOut ); // subunit of device
);
어디서 많이 본 API 라고 생각이 드시죠.
DirectCompute 를 초기화하는 작업은 바로 전통적인 CreateDevice() API 를 사용하는 것입니다.
즉, DirectX 를 사용하는 것입니다.
이로 인해서 DirectX 는 더욱 더 넓은 범위에서 활용되어 질 것입니다.
< HLSL 의 로드 >
그 다음은 실제적으로 GPU 가 실행을 하게될 로직을 로드할 차례입니다.
이것은 워낙 다양할 수 있는 부분이기 때문에, 여기서는 간단하게 예를 들겠습니다.
#define BLOCK_SIZE 256
StructuredBuffer gBuf1;
StructuredBuffer gBuf2;
RWStructuredBuffer gBufOut;
[numthreads(BLOCK_SIZE,1,1)]
void VectorAdd( uint3 id: SV_DispatchThreadID )
{
gBufOut[id] = gBuf1[id] + gBuf2[id];
}
보통 이를 두고 ComputeShader 라고 합니다.
ComputeShader 를 위한 여러종류의 버퍼가 존재합니다.
더 많은 종류의 버퍼는 차후에 설명드리기로 하겠습니다.
StructuredBuffer 라고 정의된 키워드는 C언어의 구조체와 같은 구조를 가집니다.
즉, 개발자가 정의한 구조체입니다.
그런데 앞에 식별자가 없으면 읽기 전용이라는 의미입니다.
반면에 앞에 'RW' 라고 명시된 버퍼는 읽기/쓰기 가 가능한 버퍼라는 의미입니다.
우리는 GPU 가 처리한 결과는 읽기/쓰기가 가능해야 하기 때문에,
결과를 저장하는 버퍼는 'RW" 가 명시되어 있습니다.
최적화를 위해서 각 목적에 맞게 버퍼를 사용해야 할 것입니다.^^
< ComputeShader 의 생성 >
pD3D->CreateComputeShader( pBlob->GetBufferPointer(),
pBlob->GetBufferSize(),
NULL,
&pMyShader ); // hw fmt
CreateComputeShader() API 를 통해서 간단히 ComputeShader 를 생성할 수 있습니다.
< 입력을 위한 GPU 버퍼 만들기 >
우리가 GPGPU 를 활용하는 것은 CPU 를 활용하는 것보다 빠르게 결과를 도출하기 위해서입니다.
이를 위해서는 GPU 가 빠르게 액세스할 수 있는 버퍼가 있어야 할 것이며,
당연히 이것은 비디오 메모리에 존재해야 할 것입니다.
그래서 우리는 DirectX 인터페이스를 통해서 비디오 메모리를 생성을 합니다.
D3D11_BUFFER_DESC descBuf;
ZeroMemory( &descBuf, sizeof(descBuf) );
desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
desc.StructureByteStride = uElementSize;
desc.ByteWidth = uElementSize * uCount;
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
pD3D->CreateBuffer( &desc, pInput, ppBuffer );
주의해야 할 것은 바로 'BindFlags' 입니다.
'D3D11_BIND_UNORDERED_ACCESS' 라는 플래그를 주고 있습니다.
이것은 PixelShader 나 ComputeShader 에서 병렬적으로 실행하는 버퍼를 의미합니다.
< 뷰를 만들자!! >
버퍼 리소스를 만들었으면, 이제 이를 실제 파이프라인에서 액세스할 수 있는 매커니즘을 만들어야 합니다.
즉, ShaderResourceView 를 만들어야 합니다.
DirectX10 부터는 아래와 같이 리소스들을 다루어야 합니다.
pD3D->CreateUnorderedAccessView( pBuffer, // Buffer view is into
&desc, // above data
&pMyUAV ); // result
중요한 부분은 ViewDimension 부분입니다.
'D3D11_UAV_DIMENSION_BUFFER' 를 설정하고 있는데,
이는 ComputeShader 상에서 이 버퍼를 일반적인 버퍼로 보겠다는 의미입니다.
즉, 샘플링 작업을 전혀하지 않습니다.
이는 어떠한 수정도 없이 데이터를 있는 그대로 보존합니다.
< 실행 단계 >
이제까지는 모두 준비 단계였습니다.
이제는 실제 실행 단계에 대해서 언급해 보겠습니다.
먼저, ComputeShader 를 현재 파이프라인 스테이지에 아래와 같이 바인딩 해주어야 합니다.
pD3D->CSSetShader( pMyShader, NULL, 0 );
그 다음에는 뷰를 바인딩해야 합니다.
pD3D->CSSetUnorderedAccessViews( 0,
1,
&pMyUAV,
NULL );
이제 마지막으로 GPU 에게 현재 바인딩된 내용을 바탕으로 연산해 줄 것을 요청합니다.
pD3D->Dispatch( GrpsX, GrpsY, GrpsZ );
이제 실행의 단계가 모두 끝났습니다.
이 단계까지 끝나면, 실행 결과가 비디오 메모리에 존재합니다.
우리가 결과를 확인하기 위해서는 CPU 가 액세스할 수 있는 버퍼로 결과를 복사해야 합니다.
< 결과 복사해 오기 >
결과를 CPU 가 액세스 하기 위해서는 어떻게 해야 할까요?
이전 시간을 통해서 언급드렸듯이,
DX10 부터는 리소스에 대한 세부적인 액세스 권한에 대한 플래그를 설정할 수 있습니다.
그래서 다음과 같은 설정으로 버퍼를 만듭니다.
D3D11_BUFFER_DESC desc;
ZeroMemory( &desc, sizeof(desc) );
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.MiscFlags = 0;
pD3D->CreateBuffer( &desc, NULL, &StagingBuf );
'D3D11_CPU_ACCESS_READ' 라는 플래그를 통해서,
이 버퍼는 CPU 가 액세스 할 수 있는 형태로 만듭니다.
그리고 'D3D11_USAGE_STAGING' 라는 플래그를 통해서
단순히 비디오 메모리에 있는 내용을
CPU 도 접근 할 수 있는 메모리로 복사해오는 버퍼임을 명시합니다.
그리고 아래와 같이, 준비해둔 버퍼에 실제로 메모리를 복사해 옵니다.
pD3D->CopyResource( StagingBuf, pBuffer );
마침내 우리는 GPU 에 의해서 처리된 결과를 확인할 수 있게 되었습니다.
< 마치며...>
지금까지 DirectCompute 를 활용하는 일련의 절차에 대해서 살펴보았습니다.
DirectX11 의 API 가 생소해서 어려워 보일 수 있지만,
실제로 DirectCompute 의 절차는 그리 복잡하지는 않습니다.
현재 DirectCompute 의 활용은 SDK 샘플에 'NBodyGravity' 라는 이름으로 들어있습니다.
제가 여기에 대해서 자세히 언급드리면 좋겠지만,
그것은 차후로 미루기로 하겠습니다.^^
참고 자료
http://microsoftpdc.com/Sessions/P09-16
본 내용은 위의 PDC 를 참고해서 만들었습니다.
| [DX11_#5]DirectX11의 활용 사례(1/3) (4) | 2010/06/24 |
|---|---|
| [JumpToDX11-13] Tessellation 등장. (0) | 2010/06/15 |
| [JumpToDX11-12] DirectCompute 의 절차. (0) | 2010/04/26 |
| [JumpToDX11-11] DirectCompute 를 위한 한걸음! (0) | 2010/02/11 |
| [JumpToDX11-10] GPGPU 를 위한 DirectCompute. (2) | 2010/01/27 |
| [JumpToDX11-9] Multi-threaded Rendering 을 위한 API. (0) | 2010/01/11 |
[numthreads( 256,1,1) ]
void VectorAdd( uint3 id: SV_DispatchThreadID )
{
gBufOut[id] = gBuf1[id] + gBuf2[id];
}
| [JumpToDX11-13] Tessellation 등장. (0) | 2010/06/15 |
|---|---|
| [JumpToDX11-12] DirectCompute 의 절차. (0) | 2010/04/26 |
| [JumpToDX11-11] DirectCompute 를 위한 한걸음! (0) | 2010/02/11 |
| [JumpToDX11-10] GPGPU 를 위한 DirectCompute. (2) | 2010/01/27 |
| [JumpToDX11-9] Multi-threaded Rendering 을 위한 API. (0) | 2010/01/11 |
| [JumpToDX11-8] Deferred Contexts (0) | 2009/12/02 |
| [JumpToDX11-12] DirectCompute 의 절차. (0) | 2010/04/26 |
|---|---|
| [JumpToDX11-11] DirectCompute 를 위한 한걸음! (0) | 2010/02/11 |
| [JumpToDX11-10] GPGPU 를 위한 DirectCompute. (2) | 2010/01/27 |
| [JumpToDX11-9] Multi-threaded Rendering 을 위한 API. (0) | 2010/01/11 |
| [JumpToDX11-8] Deferred Contexts (0) | 2009/12/02 |
| [JumpToDX11-7] 간편해진 리소스 처리. (0) | 2009/11/18 |
CUDA와 DirectCompute 의 속도 차이는 거의 없을 것이라고 생각이 듭니다.
어차피 구조 상에서 GPU 를 활용해야 하는 것이기 때문에
두 플랫폼의 성능 상 우위를 논하기는 어려운 문제인 것 같습니다.
사실 DirectCompute 는 아직 정식으로 SDK 에 포함된 내용이 아닙니다.
그래서 아직 공개된 자료가 거의 없는 상황입니다.
CUDA 의 경우에는 이미 몇년전에 공개가 되어서 지금 가장 앞선 GPGPU 환경입니다.
CUDA 의 이점은 저보다 아시는 분들이 더 많으시겠지만,
저는 개인적으로는 XP 에서도 된다는 것입니다.
DirectCompute 는 XP 에서 실행이 되지 않습니다.
물론 DirectCompute 를 지원하는 그래픽카드에서만 실행되겠지만,
그 또한 OS 에서 지원해 주지 않으면, 실행되지 않는다는 것입니다.
반면 CUDA 쪽은 XP 지원에 대한 포럼이 있을 정도로 활용되고 있는 상황입니다.
CUDA 의 단점은 역시 자사의 그래픽카드만 실행할 수 있다는 것입니다.
엔비다아 계열의 카드만 지원되기 때문에 게임과 같은 대중을 목표로 하는 프로젝트에서는 쉽게 적용하기 어렵습니다.
DirectCompute 의 경우에는 모든 밴더들이 이를 지원해야하는 좀 강제적이기 때문에 게임쪽에서는 DirectCompute 를 선택하는 것이 좋을 것이라 생각이 됩니다.
DirectCompute 는 아직 문법적인 내용은 많이 공개가 되지 않았지만,
HLSL 이라는 쉐이더 기반의 언어를 사용하기 때문에,
아무래도 게임 개발자들쪽에 포커스가 간 것이 사실입니다.
아직 계속 발전 중인 분야이니, 좀 더 지켜보면 좋을 것 같습니다.^^
| [JumpToDX11-11] DirectCompute 를 위한 한걸음! (0) | 2010/02/11 |
|---|---|
| [JumpToDX11-10] GPGPU 를 위한 DirectCompute. (2) | 2010/01/27 |
| [JumpToDX11-9] Multi-threaded Rendering 을 위한 API. (0) | 2010/01/11 |
| [JumpToDX11-8] Deferred Contexts (0) | 2009/12/02 |
| [JumpToDX11-7] 간편해진 리소스 처리. (0) | 2009/11/18 |
| [DX11_#4]텍스트, 버튼 출력 (0) | 2009/11/10 |
<<연재 일시 중단>>
vs 2010 beta2 가 스마트기기 개발환경을 지원하고 있지 않은 관계로 연재를 일시 중단 합니다.
미리 확인 하지 않고 연제를 시작한 점 사과드립니다.
차후에 스마트기기 개발환경이 지원되는 대로 다시 하도록 하겠습니다.
1. 들어가며…
안녕하세요.
저는 이번에 vsts2010에 참여하게 된 이석준 이라고 합니다.
앞으로 잘 부탁 드리겠습니다.
이런 공인된 장소를 글을 쓰는 것은 첨이다 보니 무척 부담이 많이 밀려오는 군요.
혹시 잘못된 부분이나 미흡한 부분이 있으면 바로 지적해 주시면 감사하겠습니다.
(제가 국어가 약해서 가끔 안드로메다틱한 문법이 나올 수도 있으니 이해 안 되는 문장은 반드시 지적을 해주시면 감사하겠습니다. ㅡ.ㅡ; )
VS상의 윈도우모바일(이하 wm) 개발환경은 리눅스나 기타 임베디드 개발환경에 비해 빠르고, 편리하고, 쉽습니다. 기존의 win32api, .Net 코드를 쓸 수 있음은 물론 WTL,MFC등과도 많은 부분의 코드가 호환이 됩니다. 모바일이나 임베디드 에서는 대부분 3D 랜더러로 opengl-es가 많이 사용되는 것으로 알려져 있습니다. 그러나 게임을 만들 때는 direct3d를 많이 사용합니다. Direct3d Mobile 이하 D3dm 을 사용하면 기존의 Direct3d코드를 그대로 활용할 수 있는 장점이 있습니다. 지금부터 약 10회로 나누어서 wm6상에서의 개발환경부터 오픈소스공개 랜더엔진인 irrlicht3d의 d3dm용 드라이버까지 제작을 해보도록 하겠습니다.
2. 준비물
wm6sdk , active sync 두 가지가 필요합니다.
여기서 wm6sdk 은 소프웨어 개발킷 이므로 애뮬레이터와 샘플소스코드는 물론 VS용 라이브러리와 클래스위져드관련 환경파일들이 모두 포함된 형태입니다.
요즘 나오는 옴니아2등의 폰에는 6.1버전이라고 되 있는데요 따로 6.1sdk는 존재하지 않습니다. 검색해보시면 DDK가 나와있는 것을 볼 수 있는데요.
DDK와 sdk가 다른 점은 DDK는 VS관련 라이브러리 파일제외하고 에뮬레이터와 샘플소스 각종 유틸리티 툴이 업그래이된 것이라고 보시면 됩니다.
요약하자면 wm6sdk 설치후 원하시는 타겟의 DDK나 에물레이터 image를 받아서 먼저 SDK설치하신 다음에 설치 하시면 됩니다.
만약 특정스마트기기의 특정한 기능을 이용하고 싶으시면 이 위에 다시 해당 기기용 sdk를 설치해서 사용하시면 됩니다.
그러면 특정 스마트기기용 추가 API Set 이 설치됩니다.
active sync는 스마트기기와 VS개발환경간의 통신수단을 해주는 역할을 하므로 Sdk를 설치 하기 이전에 이것부터 설치를 해주셔야 합니다.
wm6가 설치된 스마트기기는 기본적으로 이미 설치되 있으니 개발 pc에서 설치를 한번 해주시면 됩니다.
3. Hello wm6!!
모든 설치가 순조롭게 끝나고 새프로잭트->스마트기기(Smart Device) 항목이 나온다면 설치가 성공한 것 입니다.
그럼 간단한 프로그램부터 만들어 보도록 하죠. 아래와 같이 Smart Device->Win32 Smart Device Project를 선택합니다.
그 다음 platforms 탭에서 windows mobile6 sdk를 추가 시켜줍니다.
프로잭트 위져드 덕택에 자동으로 기본프레임웍까지 코드가 작성되서 나오니 편리 하지 않습니까? ^^;
4. Deployment
항목을 만드는 양식은 다음과 같습니다.
원본파일이름|원본파일이 있는 경로|파일이 카피될 원격경로|0
Remote Directory 에는 스마트기기에서 실행파일이 실행될 경로를 정해줍니다. 그러나 주의 할점은 어플상에서 파일을 참조할경우 경로는 여기서 지정해준 원격경로가 아닌 저장장치단위의 최상위디랙토리인 My Device/ 기준으로 경로를 잡게됩니다.
참고로 %CSIDL_PROGRAM_FILES% 는 My Device/Program files를 가리킵니다.
실행파일은 Deployment ->Additional Files에서 추가 하지않고 디버깅->Remote Executable 에 정해진 파일이 원격실행 디랙토리에 자동으로 카피가 됩니다.
5. to be continued…
다음에는 샘플로 제공된 basicApp를 분석해 간단한 이미지 뷰어를 만들어 보도록 하겠습니다.
| .NET 기반에서 공개소스 게임엔진 포팅하기 (0) | 2010/07/25 |
|---|---|
| [d3dm 기초] 1. wm6.x 개발환경 세팅 (4) | 2009/12/26 |
Visual Studio 2010 Beta 2 버전에서 Smart Device 개발이 가능한 것인가요? 아니면 Visual Studio 2008 버전 기준인가요? 혹시 Visual Studio 2010 Beta2버전이 설치되어 있는 이후에 wm6sdk를 설치해야 하나요?
2010베타2는 아직 스마트기기 미지원입니다.
정식판에서는 지원될듯합니다.
| [JumpToDX11-10] GPGPU 를 위한 DirectCompute. (2) | 2010/01/27 |
|---|---|
| [JumpToDX11-9] Multi-threaded Rendering 을 위한 API. (0) | 2010/01/11 |
| [JumpToDX11-8] Deferred Contexts (0) | 2009/12/02 |
| [JumpToDX11-7] 간편해진 리소스 처리. (0) | 2009/11/18 |
| [DX11_#4]텍스트, 버튼 출력 (0) | 2009/11/10 |
| [JumpToDX11-6] 커맨드(Command)... (0) | 2009/11/09 |
이번 회의 설명을 위해서 API 를 다음과 같이 크게 나누어 보았습니다.
· Thread unsafe API
· Thread safe API
· Free threaded API
Thread unsafe 한 경우에는 멀티스레드들이 동시에 호출할 수 있지만,
이들에 대한 안정성에 대해서는 전혀 보장하지 않습니다.
결과가 갑자기 이상할 수도 있고, 예측 불가능한 상황을 연출할 수도 있습니다.
주로 즉시즉시 상황을 만들어야 할때 사용될 수 있을 것입니다.
Thread safe 한 API 는 어떤 동기화 모델에 의해서 API 가 보호되어집니다.
여러 스레드에서 API 를 호출하더라도, 그들의 안정적인 동작을 보장한다는 의미입니다.
동기화 작업이 별도로 있기 때문에 느려질 수 있다는 단점이 있습니다.
Free threaded 한 API 는 여러 스레드에서 호출을 하더라도,
어떠한 동기화 모델 없이도 API 가 안정적으로 동작한다는 것을 의미합니다.
그렇기 때문에 아주 높은 성능 향상을 얻을 수 있습니다.
< 기존의 리소스 처리 >
멀티스레드 기반의 렌더링으로 가는 첫번째 길은 리소스 부분입니다.
PC 가 발전하면서 성능적으로나 용량적으로 많은 발전을 거듭했습니다.
더블어 게임에서 사용되는 리소스의 용량도 크게 증가했습니다.
멀티스레드 처리가 어느 정도 자리를 잡으면서,
현재 많은 게임들은 이들 리소스에 대한 처리를 별도의 스레드에서 처리하기도 합니다.
멀티스레드 기반으로 리소스를 로딩하고 있지만,
실제로는 많은 부분이 메인스레드( 여기서는 Render Thread )에 의존하여 작업이 수행되고 있습니다.
리소스를 생성하기 위해서는 반드시 Create, Lock & Unlock 작업이 필요합니다.
< 여기서 잠깐...>
사실 위의 그림의 경우에는 일반적으로 사용되는 구조로 보기 어렵습니다.
그림은 거의 순차적인 처리 구조이기 때문에,
이런 경우라면 굳이 저렇게 사용할 필요가 없습니다.
실제로 많은 게임들은 텍스쳐가 아직 로딩 중이라면,
Default-Material 을 적용해서 폴리곤을 렌더링하도록 구현하기도 합니다.
즉, Render Thread 가 쉴새 없이 계속 커맨드를 생성하는 구조입니다.^^
그리고 위의 예는 간단한 설명을 위한 것입니다.
개발자분들마다 개성 강한 여러 방법들이 존재하시겠죠? ^^
< 간편해진 리소스 관련 커맨드 생성 >
우리가 DirectX 에서 사용하는 대부분의 리소스 작업은 사실 Free Threaded 합니다.
리소스 처리를 위해서 특별한 동기화 처리가 API 레벨에서는 필요하지 않습니다.
( 개발자의 몫입니다. )
그런데 위의 그림처럼 그 동안은 커맨드를 생성해주는 인터페이스가 오직 하나였기 때문에
메인 스레드에 의존해서 처리할 수 밖에 없었습니다.
두번째 시간에 저는 Device와 DeviceContext 에 대해서 설명을 드렸습니다.
기억이 나지 않으시는 분들은 다시 살펴보시기 바랍니다.^^
요약해드리자면, DirectX11 에서는 Free threaded 한 API 와 그렇지 않은 API 들을 분리했습니다.
그 Free threaded 한 부분에 바로 리소스 처리가 있습니다.
앞서 우리는 Free threaded 의 이점에 대해서 짧게 언급했었습니다.
위의 그림에서,
이제는 Loader therad 는 굳이 메인 스레드( Render thread ) 에 의존하지 않아도,
순차적으로 리소스 관련 커맨드들을 생성시킬 수 있습니다.
커맨드들이 생성되는 순서는 Free threaded 한 경우에는 중요하지 않기 때문에,
빠른 속도로 처리할 수 있습니다.
특히나, 메인스레드가 별도로 다른 작업을 수행해서 커맨드를 생성시키는 작업이 있다고 해도,
그것과는 별도로 커맨드 생성 작업을 수행할 수 있습니다.
( 커맨드 생성을 위한 대기 시간이 짧아졌다고 할 수 있습니다. )
이로써, 이제는 조금 더 멀티스레딩 형식에 가까워졌다고 할 수 있습니다.
리소스 처리를 이렇게 분리하는 것은
멀티스레드 기반으로 렌더링으로 가는 중요한 기반을 제공해 주었습니다.
< 다음 회에서는.... >
다음 회부터는 이제 멀티스레드 기반으로 렌더링 관련 커맨드를 생성하는 것을 살펴볼 것입니다.
| [JumpToDX11-9] Multi-threaded Rendering 을 위한 API. (0) | 2010/01/11 |
|---|---|
| [JumpToDX11-8] Deferred Contexts (0) | 2009/12/02 |
| [JumpToDX11-7] 간편해진 리소스 처리. (0) | 2009/11/18 |
| [DX11_#4]텍스트, 버튼 출력 (0) | 2009/11/10 |
| [JumpToDX11-6] 커맨드(Command)... (0) | 2009/11/09 |
| [JumpToDX11-5] 새로운 시대를 여는 DirectX11... (6) | 2009/11/02 |
DX9에서 DXUT라는 것은 SDK의 소스에서 그리크게 눈에 띄지 않았습니다.
DXUT라는 것은 DX에서 제공하는 프레임 워크라고 생각하시면 됩니다.
DX11의 모든 예제들이 DXUT를 이용해 작성이 되어있기 때문에 기본적인 구조를 익혀두시는 것이 좋습니다.
함수명만 보아도 함수의 용도를 한눈에 알 수 있기 때문에 보시는데 어려움은 없으실 것 입니다.
void InitApp()
{
g_SettingsDlg.Init( &g_DialogResourceManager ); // 디바이스 Setting Dlg 초기화
g_HUD.Init( &g_DialogResourceManager ); // Dlg기본 컨트롤 초기화
g_SampleUI.Init( &g_DialogResourceManager );
g_HUD.SetCallback( OnGUIEvent ); // 컨트롤 콜백함수 등록
int iY = 30;
int iYo = 26;
아래와 같이 버튼 추가하고 버튼을 클릭하면 'OnGUIEvent'함수의 case문에서 해당하는 함수를 호출합니다.
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 0, iY, 170, 22 );
g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 0, iY += iYo, 170, 22, VK_F3 );
g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 0, iY += iYo, 170, 22, VK_F2 );
g_SampleUI.SetCallback( OnGUIEvent );
iY = 10;
}
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{
switch( nControlID )
{
case IDC_TOGGLEFULLSCREEN:
DXUTToggleFullScreen(); // 전체화면, window모드 간의 toggle
break;
case IDC_TOGGLEREF:
DXUTToggleREF(); // HAL과 reference device types 간의 toggle
break;
case IDC_CHANGEDEVICE:
g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() ); // 디바이스 변경
break;
}
}
이전과는 확연하게 다른 방법으로 텍스트를 출력하고 있습니다.
DX9에서 사용하던 'CD3DFont'를 사용하지 않고, 'CDXUTTextHelper'를 사용해 생성한 변수로 화면에 텍스트를 출력합니다.
[DX9]
CD3DFont* pFont;
pFont->DrawText( X, Y, color, str );
[DX11]
void RenderText()
{
g_pTxtHelper->Begin();
g_pTxtHelper->SetInsertionPos( 5, 5 ); // 출력 위치
g_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) ); // 폰트 색상
아래와 같이 'DXUTGet'으로 시작되는 함수들을 이용해 여러가지 정보를 얻어올 수 있습니다.
g_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) ); // FrameStats출력
g_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() ); // Device state출력
g_pTxtHelper->DrawTextLine( L"Font Test" ); // 기본적인 텍스트 출력
g_pTxtHelper->End();
}
이런 작업들을 거치면 아래와 같이 화면에 간단한 디바이스 정보와 버튼을 출력할 수 있습니다.
| [JumpToDX11-8] Deferred Contexts (0) | 2009/12/02 |
|---|---|
| [JumpToDX11-7] 간편해진 리소스 처리. (0) | 2009/11/18 |
| [DX11_#4]텍스트, 버튼 출력 (0) | 2009/11/10 |
| [JumpToDX11-6] 커맨드(Command)... (0) | 2009/11/09 |
| [JumpToDX11-5] 새로운 시대를 여는 DirectX11... (6) | 2009/11/02 |
| [DX11_#3]기본적인 설정 (0) | 2009/10/22 |
| [JumpToDX11-7] 간편해진 리소스 처리. (0) | 2009/11/18 |
|---|---|
| [DX11_#4]텍스트, 버튼 출력 (0) | 2009/11/10 |
| [JumpToDX11-6] 커맨드(Command)... (0) | 2009/11/09 |
| [JumpToDX11-5] 새로운 시대를 여는 DirectX11... (6) | 2009/11/02 |
| [DX11_#3]기본적인 설정 (0) | 2009/10/22 |
| [DX11_#2]D3D Buffer( 2 / 2 ) (0) | 2009/10/13 |
사실 DirectX11 의 많은 부분은 X-Box360 에서 이미 사용되고 있습니다.
X-Box360 의 ComputeShader 지원은 모르겠으나, 나머지 두가지는 지원하고 있습니다.
X-360을 언급한 이유는 이들 기능이 이미 어느 정도 검증을 받은 기능이라는 점을 강조하고 싶어서 입니다.
( 물론 최신 버전이기 때문에 더 빨라지고, 더 좋아진 부분이 많습니다.^^ )
DirectX11 의 큰 패러다임은 '놀지마' 입니다.
이제는 멀티코어(CPU)와 GPU에게 최대한 많은 일을 시킬 수 있는 구조로
하드웨어를 구성했고, 그것을 기반으로 해서 런타임과 API 를 설계하고 만들었습니다.
DirectX9 까지는 API 가 변화를 주도했다면,
이제는 DirectX API 변화를 하드웨어가 주도하고 있다고 볼 수 있습니다.
그러다보니 자연스럽게 API 도 더욱 하드웨어에 가깝게 설계되었습니다.
대표적으로 OutputMerge 를 지칭하는 OMxxxx 계열과
InputAssembler 를 지칭하는 IAxxxx 계열 등이 있습니다.
혹시 DirectX8-->9 로 포팅 작업을 하셨던 분들이 이 글을 읽으시는지 모르겠습니다만,
8-->9 의 변화는 API 차원에서 변화가 컸기 때문에 매우 단순했습니다.
하지만 이제는 하드웨어가 크게 변했기 때문에,
단순 포팅 작업 정도로 생각하시면 큰 오산입니다.
물론 단순히 API 만 교체해도 성능 향상을 얻을 수 있습니다.
DirectX11 은 하드웨어 오버헤드를 줄이기 위해 많은 최적화 작업을 수행했다고 합니다.
새로운 DirectX 의 시대가 왔다는 느낌이 드시나요? ^^
| [DX11_#4]텍스트, 버튼 출력 (0) | 2009/11/10 |
|---|---|
| [JumpToDX11-6] 커맨드(Command)... (0) | 2009/11/09 |
| [JumpToDX11-5] 새로운 시대를 여는 DirectX11... (6) | 2009/11/02 |
| [DX11_#3]기본적인 설정 (0) | 2009/10/22 |
| [DX11_#2]D3D Buffer( 2 / 2 ) (0) | 2009/10/13 |
| [DX11_#1]D3D Buffer( 1 / 2 ) (0) | 2009/09/22 |
중요한 것은 XP 유저가 더 많은데 XP 유저는 DirectX 10 이상의 게임을 돌릴 수 없다는 것이죠. DX8->9 업그레이드는 해도 그만 안해도 그만이었지만 9->10,11은 하면 XP 유저를 잃습니다. 새로운 DirectX 가 온 것은 맞을지 몰라도 새로운 시대는 아직 아네요.
안녕하세요. 유익한 포스팅 잘 보고 갑니다만, 조금 아쉬운 부분이 있어 comment 를 남깁니다. 명색이 '공식 팀 블로그' 인데 조금은 formal 한 용어와 분위기의 포스팅이 되었으면 좋겠습니다. (구체적으로 "이미지 출처 : (아마도)ATI"![]()
앞으로도 계속 좋은 포스팅 부탁드립니다.
대체 왜 DX10 부터 XP에 대한 지원을 하지 않는 것인가?
뭐 결론부터 따지자면 "지원이 불가능 해서" 가 아니라
"새 운영체제 판매를 위해서" 가 아닐까 싶다..
GPU Tessellation.
Compute Shader.
Multi-threaded rendering.
이 세가지 XP에서 충분히 구현 가능하다..
(안될게 없지 않은가? 있다면... 왜 안되는지 말을 해보라)
새로운 OS가 나오면 최대한 팔아먹어야 하니까..
M$는 이래서 안된다.. 물론 나도 회사에서 M$의 노예가 되어
어쩔수 없이 M$기반의 프로그램을 짜야 하지만..
솔직히 가끔 아니다 싶을때가 많다..ㅎㅎ
DirectX SDK(August 2009)에 포함된 'EmptyProject11'을 기준으로 기본 적인 DirectX세팅에 대해서 설명 하겠습니다.
아래와 같이 DXUT의 일반적인 설정을 하면 상황에 이벤트에 따라 해당 함수를 호출합니다.
키보드가 눌리면 Onkeyboard가 호출되고, DXUTCreateDevice로 디바이스를 생성하면 'ModifyDeviceSettings'함수가 호출되는 등 기본적으로 필요한 골격을 제공하고 있습니다.
DXUTSetCallbackFrameMove( OnFrameMove );
DXUTSetCallbackKeyboard( OnKeyboard );
DXUTSetCallbackMouse( OnMouse );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
DXUTSetCallbackDeviceRemoved( OnDeviceRemoved );
DX9까지는 DX에 디파인된 버젼으로 어플리케이션에서 실행이 가능한 버젼인지 체크 후 버젼이 맞지 않으면 프로그램을 종료해 버렸습니다.
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
그러나 아래와 같이 초기화를 하면 어렵지 않게 각 버젼에 대해 깔끔하게 처리가 가능합니다.
여러개의 버젼을 세팅하는 것에 대해 저처럼 의아하게 생각하시는 분도 계실 것 입니다.
그러나 그저 DX9과 DX11을 같이 소스에 위치를 시키면, 하위 버젼에 대한 것들은 모두 알아서 삭제되고,
DX11의 콜백은 정상적으로 설정이 됩니다.(위 아래 순서를 바꿔도 상관 없이 이와 같이 동작 합니다.)
DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );
DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );
DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );
DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );
DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );
DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );
DXUTSetCallbackD3D11DeviceAcceptable( IsD3D11DeviceAcceptable );
DXUTSetCallbackD3D11DeviceCreated( OnD3D11CreateDevice );
DXUTSetCallbackD3D11SwapChainResized( OnD3D11ResizedSwapChain );
DXUTSetCallbackD3D11FrameRender( OnD3D11FrameRender );
DXUTSetCallbackD3D11SwapChainReleasing( OnD3D11ReleasingSwapChain );
DXUTSetCallbackD3D11DeviceDestroyed( OnD3D11DestroyDevice );
첫번째 인자를 true로 설정하면 커맨드를 설정해 아래와 같은 기능을 사용 할 수 있습니다.
(각 버젼에 특화된 커맨드도 몇 가지 있습니다.)
'-fullscreen'=> 전체화면으로 설정
'-width:800 -height:600' => AppWindow의 넓이, 높이를 800x600으로 설정
(이 커맨드를 설정하면 DXUTCreateDevice의 화면 사이즈는 무시됩니다.)
두번째 인자는 에러 메세지 박스 출력
세번째 인자는 여분의 커맨드라인 파라메타세팅(default:NULL)
DXUTInit( true, true, NULL );
첫번째 인자가 true이면 전체 화면 모드에서 커서가 보이도록 설정.
두번째 인자가 true이면 전체 화면 모드에서 커서가 화면을 벗어나지 못하도록 설정.
(테스트 했을때 두개의 인자 모두 true와 false일때의 차이점을 느끼지 못했습니다.)
DXUTSetCursorSettings( true, true );
설정한 타이틀로 윈도우 생성
DXUTCreateWindow( L"EmptyProject11" );
'하드웨어 레벨10'으로 디바이스를 생성
(Feature level관련은 조진현님의 글을 참고하시기 바랍니다.)
두번째 인자가 true이면 윈도우모드, false이면 풀스크린모드 입니다.
(테스트 했을때 false일때도 풀스크린 모드로 변경이 되지 않았습니다.)
세번째, 네번째 인자로 화면의 넓이 높이를 설정할 수 있습니다.
DXUTCreateDevice( D3D_FEATURE_LEVEL_10_0, true, 640, 480 );
DXUT 메인루프 실행
DXUTMainLoop();
리턴되는 값으로 D3D초기화, 디바이스 상태 등을 알 수 있습니다.
'0'이면 정상이고, 그 이외의 값일경우 DX help파일에서 에러 내용을 확인하시기 바랍니다.
DXUTGetExitCode();
샘플을 실행하면, 예상대로 그저 윈도우안에 세팅된 타이틀과, 파란 화면만 덩그라니 출력됩니다.
첫 샘플 분석이기 때문에 최대한 간단한 함수까지 설명을 적었습니다.
다음 글 부터는 특이사항이 없는한 이번에 설명했던 함수에 대해서는 넘어가도록 하겠습니다.
DXUTSetCursorSettings, DXUTCreateDevice함수의 설명과 테스트 결과가 다른 이유는 DirectX Help의 설명을 적었으나 테스트 결과 문서대로 동작하지 않았던 것 입니다.
문제가 있는 것이 맞다면 다음 버젼에는 수정될 것으로 예상됩니다.
다음 글은 좀 더 화면에 보이는 것이 많은 것으로 올리도록 하겠습니다.
| [JumpToDX11-6] 커맨드(Command)... (0) | 2009/11/09 |
|---|---|
| [JumpToDX11-5] 새로운 시대를 여는 DirectX11... (6) | 2009/11/02 |
| [DX11_#3]기본적인 설정 (0) | 2009/10/22 |
| [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 |
3) Constant Buffer
Dx10에서 생긴 ‘Constant Buffer’는 ‘Shader’를 사용할 때 비효율적이고 지속적인 업데이트로 인해 성능을 떨어트리는 현상을 극복하기 위해 도입 되었습니다. 이를 이용해 API와 하드웨어가 상수를 효율적으로 조작해, 귀중한 GPU의 bandwidth와 CPU의 사용량을 최소화 할 수 있습니다.
Shader Constant들을 일괄적으로 관리해 shader constant data 를 관리하기 위해서 발생하는 bandwidth overhead 를 줄여 줍니다.
예전에는 constant 를 등록할 때 4개의 component 를 가진 상수를 등록하는게 기본이었습니다. 즉 float4 가 costanat 설정의 최소 단위였습니다. 하지만 이제는 float 하나만 등록하는 것이 가능합니다.
Shader-constant buffer의 생성은 이전 글에서 언급 했던 것처럼 ‘D3D11_BUFFER_DESC’의 BindFlags를 ‘D3D11_BIND_CONSTANT_BUFFER’로 설정하면 됩니다.
// Define the constant data used to communicate with shaders.
struct VS_CONSTANT_BUFFER
{
D3DXMATRIX mWorldViewProj;
D3DXVECTOR4 vSomeVectorThatMayBeNeededByASpecificShader;
float fSomeFloatThatMayBeNeededByASpecificShader;
float fTime;
float fSomeFloatThatMayBeNeededByASpecificShader2;
float fSomeFloatThatMayBeNeededByASpecificShader3;
};
D3D11_BUFFER_DESC BufDesc;
BufDesc.ByteWidth = sizeof( VS_CONSTANT_BUFFER );
BufDesc.BindFlags = D3D10_BIND_CONSTANT_BUFFER
그러나 Index, Vertex Buffer는 다른 ‘D3D11_BIND_CONSTANT_BUFFER’의 열거형 변수들과 함께 ‘or연산’으로 사용할 수 있으나 ‘D3D11_BIND_CONSTANT_BUFFER’는 다른 flag와 함께 사용 할 수 없습니다.
Shader-constant buffer 파이프라인에 bind할 때 아래 중 한 개를 사용합니다.
ID3D11DeviceContext::GSSetConstantBuffers,
ð ‘Geometry shader pipeline state’ 설정.
ID3D11DeviceContext::PSSetConstantBuffers,
ð ‘Pixel shader pipeline state’ 설정.
ID3D11DeviceContext::VSSetConstantBuffers
ð ‘Vertex shader pipeline state’ 설정.
쉐이더가 Shader-constant buffer를 읽게 하기 위해, 고유의 HLSL함수를 사용합니다.
실질적으로 DX10에서 DX11로 넘어오며 바뀐 점을 딱히 찾지는 못하고, Dx Help파일을 번역하고 검색한 내용을 약간 첨부한 정도가 되었습니다.
추후에 더 알게 되는 것이 있으면 추가하도록 하겠습니다.
| [JumpToDX11-5] 새로운 시대를 여는 DirectX11... (6) | 2009/11/02 |
|---|---|
| [DX11_#3]기본적인 설정 (0) | 2009/10/22 |
| [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 |
안녕하세요. Q3에 합류한 안승근입니다.
앞으로 DX11에 와서 변경된 내용 중 기초적인 부분을 담당하여 글을 올리도록 하겠습니다.
대부분의 내용은 DX9와 비교해 변경된 사항에 대해 언급 하도록 하겠습니다.
글을 읽으시다 틀린 내용에 대해서는 코멘트를 주시면 감사하겠습니다.
D3D11에는 아래와 같이 총 3개의 버퍼 타입이 있습니다.
Buffer Type: Vertex Buffer, Index Buffer, Constant Buffer
1) Vertex Buffer
각 정점의 정보를 직접적으로 저장해놓고 사용하는 방식.
간단히 사용할 수 있으나 중복된 정점의 위치를 여러개 저장하고 사용하는 등 능률은 높지 않다.
2) Index Buffer
Index로 Vertex Buffer의 정점 정보를 얻어 사용할 수 있다.
Vertex Buffer와 Index Buffer는 같은 정점에 대해서는 Index로 위치 정보를 공유해서 사용하기 때문에 능률이 높아진다.
* DX9와 DX11의 버퍼 생성시 차이점
IDirect3DDevice9::CreateVertexBuffer
ð ID3D11Device::CreateBuffer
DX9에서는 아래와 같이 각각의 버퍼를 생성하는 함수가 따로 존재하였습니다.
if( FAILED( g_pd3dDevice->CreateVertexBuffer( 50*2*sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
{
return E_FAIL;
}
if( FAILED( g_pd3dDevice->CreateIndexBuffer( 12 * sizeof(MYINDEX),
0, D3DFMT_INDEX16,
D3DPOOL_DEFAULT, &g_pIB, NULL ) ) )
{
return E_FAIL;
}
정점을 생성하는 방법이 DX11에 와서는 한개의 함수로 통합해서 사용하고 아래와 같이 D3D11_BUFFER_DESC에 버퍼 생성에 필요한 옵션을 넣었고, 특히 멤버변수인 BindFlags를 변경해 어떤 버퍼를 생성할지 정할 수 있도록 하였습니다.
위의 함수들을 다시 보면 왜 굳이 나눠 놓았을까 싶을 정도로 함수 이름만 다를뿐 파라미터가 거의 동일합니다.
// Define the data-type that
// describes a vertex.
struct SimpleVertexCombined
{
D3DXVECTOR3 Pos;
D3DXVECTOR3 Col;
};
// Supply the actual vertex data.
SimpleVertexCombined verticesCombo[] =
{
D3DXVECTOR3( 0.0f, 0.5f, 0.5f ),
D3DXVECTOR3( 0.0f, 0.0f, 0.5f ),
D3DXVECTOR3( 0.5f, -0.5f, 0.5f ),
D3DXVECTOR3( 0.5f, 0.0f, 0.0f ),
D3DXVECTOR3( -0.5f, -0.5f, 0.5f ),
D3DXVECTOR3( 0.0f, 0.5f, 0.0f ),
};
// Create indices.
unsigned int indices[] = { 0, 1, 2 };
// Setup constant buffers
D3D11_BUFFER_DESC BufDesc;
// Vertex Buffer Size
BufDesc.ByteWidth = sizeof( SimpleVertexCombined ) * 3;
// Index Buffer Size
// BufDesc.ByteWidth = sizeof( unsigned int ) * 3;
BufDesc.Usage = D3D11_USAGE_DYNAMIC;
BufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; // D3D11_BIND_INDEX_BUFFER
// , D3D10_BIND_CONSTANT_BUFFER...
BufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
BufDesc.MiscFlags = 0;
pd3dDevice->CreateBuffer( &BufDesc, NULL, &g_pMirrorVertexBuffer );
정점을 저장하는 버퍼역시 DX9에서는 VertexBuffer, Index Buffer가 각각 나누어져 있었던 것이 DX11에서는 한개로 통합되었습니다.
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // 정점버퍼
LPDIRECT3DINDEXBUFFER9 g_pIB = NULL; /// 인덱스버퍼
ID3D11Buffer* g_pVertexBuffer = NULL;
* DX10과 DX11의 버퍼 생성시 차이점
DX10과 DX11은 사실상 함수 이름외에는 변한 것이 없습니다.
아래와 같이 사용하는 함수의 이름 중 DX의 버젼을 나타내는 숫자가 '10'에서 '11'이 된 것 외에는 사용되는 모든 함수가 ‘파라미터’와 ‘리턴타입’까지 동일하므로 DX11이라고 해서 따로 알아야 할 내용은 없습니다.
ID3D10Device::CreateBuffer
ð ID3D11Device::CreateBuffer
버퍼에 관련된 내용 뿐만 아니라 대부분의 함수들이 DX10과 DX11은 거의 비슷한 형태를 지니고 있습니다. 따라서 특별한 경우가 아니면 DX9와 비교해 변경된 것만을 적도록 하겠습니다.
다음 번의 글에는 Constant Buffer에 대해서 올리도록 하겠습니다.
| [DX11_#3]기본적인 설정 (0) | 2009/10/22 |
|---|---|
| [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 |
이번 회에서는 일단 소스를 좀 나열해 보겠습니다.
일단 변수들은 다음과 같습니다.
이어지는 상황은 다음과 같습니다
그리고 다음에 이어지는 상황을 다시 보겠습니다.
이어졌던 소스는 Depth-Stencil Buffer 생성을 위한 작업이였습니다.
역시나 낯선 개념이 등장하는데, 바로 'View' 입니다.
우리가 앞서 생성했던 BackBuffer 와 Depth-Stencil Buffer 에는 CreatexxxxxxxView() 형태로
작업을 해주고 있습니다.
하나의 뷰는 렌더링 작업 중에 파이프라인에서 접근할 수 있는 리소스 일부분을 의미합니다.
더 정확한 개념을 위해서 아래의 계층구조를 한번 살펴보시기 바랍니다.
우리가 사용하는 모든 리소스들은 사실 ID3D11Resource 를 상속받아서 구성됩니다.
텍스쳐나 각종 버퍼 등이 이에 속한다고 할 수 있습니다.
( ID3D11Buffer, ID3D11Texture )
ID3D11View 를 상속받아서 구현되는 것들은 ID3D11RenderTargetView, ID3D11DepthStencilView, ID3D11ShaderResourceView 가 있습니다.
나열하고 보니깐 약간 감이 오시지 않으십니까?
이렇게 분리가 되었는데, 사실 ID3D11View 는 ID3D11View::GetResource() 라는 멤버함수를 가지고 있습니다.
결국 ID3D11View는 ID3D11Resource 와 개념적으로 메모리 데이터는 동일하다고 볼 수 있습니다.
그러다 보니 이 두가지 인터페이스를 구별해서 설명하기가 무척 난해합니다.
비슷하면서도 실질적으로 수행되는 역활에는 엄연한 구분이 있으니 말이죠...
‘이렇게 분리함으로써 역할 구분이 명확해서 코드의 품질이 향상되었다’ 라고 말할 수 있습니다.
조금 더 좋은 방향으로 생각해 본다면,
아마도 내부적으로 조금 더 최적화 된 위치에 메모리를 할당해 주지 않을까? 라는 의심도 해봅니다.
( 왜 그런지 이유를 꽤 오래 생각했지만, 답을 찾지 못했습니다..T.T )
참고로 얘기드리면,
DirectX9 버전까지 유용하게 사용되던 메모리 풀의 개념이 이제는 CPU 에서 읽기/쓰기 작업,
GPU 에서 읽기/쓰기 작업이 가능여부를 설정하는 개념형태로 변경되었습니다.
이것에 대한 얘기는 다음 번에 저나 다른 분이 해주실 겁니다.
( DirectX11 파트에는 저 말고도 한분이 더 계십니다…^^ )
위의 코드에서 View 계열들은 GPU 만 읽기/쓰기 작업이 가능한 형태로 그래픽 카드상에
메모리를 할당했습니다.
결국 위의 작업은 바로 아래에 나오는 작업을 위해서 필요했던 것입니다.
보시듯이 모두 View 계열의 인터페이스를 설정했습니다.
< 마치면서... >
다음주는 한주 쉬게 될 것입니다.
스터디 내부 발표가 있어서...쿨럭~
| [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 |
| [JumpToDX11-1] 사라진 Direct3D 오브젝트를 찾아서... (8) | 2009/08/17 |
그렇다는 것은 그래픽 카드에도 역시 버전이 있다는 것입니다.
Feature Level 이라는 것이 바로 그런 하드웨어의 버전 역활을 하는 것입니다.
현재 DirectX11 을 지원하는 그래픽 카드는 미출시 상태입니다.
그렇기 때문에 사실 DirectX11 프로그램은 하드웨어 가속을 시킬 수가 없습니다. ( 새로 사야하나...-_- )
DirectX9 시절에는 CreateDevice 옵션에 HAL 옵션 주면 자동(?)으로 가속되는 Device 를 생성해 주었지만,
이제는 그래픽 카드에서 구현된 버전을 정확히 얻어서,
그 Feature Level 에 맞는 Device 를 생성시켜야 합니다.
예를 들면 제가 가진 컴퓨터가 DirectX 10 버전을 지원하는 그래픽 카드인데,
Feature Level 에 DirectX 10.1 버전과 하드웨어 가속 옵션을 주어서
Device 생성을 요구하면, 그것은 실패하게 됩니다.
그렇다는 것은 Feature Level 10 를 설정해 주어서 Device 를 생성 시켜주어야 한다는 의미입니다.
이렇게 하면 우리는 DirectX 11 API 를 이용해서 낮은 버전의 DirectX 버전을 사용하는
그래픽 카드를 제어할 수 있을 것입니다.
아래의 그림이 이해에 도움이 되었으면 좋겠습니다.
그렇다면 좀 더 정확하게 우리가 할 일을 확장해 보면,
가장 최근의 Feature Level 부터 나열해보면서,
사용하는 그래픽 카드의 Feature Level 을 알아내는 것이 될 것입니다.
( 저는 위의 예제에서는 11버전만 고려해서 작업한 것입니다.^^ )
사실 예전에는 Device Caps 라는 개념이 있었는데,
사실 이것이 기능별로 체크했기 때문에 굉장히 반복적인 작업이였을 것이라 생각이 듭니다.
그것을 Feature Level 이라는 개념으로 단순화 시켰다고 보면 괜찮을 것 같습니다.
< 추가된 내용 >
각 Feature Level 에 대응되는 쉐이더 모델은 다음과 같습니다.
Feature Level 11.0 = Shade 5.0
Feature Level 10.1 = Shader 4.1
Feature Level 10.0 = Shader 4.0
Feature Level 9.3 = Shader 3.0
Feature Level 9.2 = Shader 2.0
Feature Level 9.1 = Shader 2.0
| [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 |
| [JumpToDX11-1] 사라진 Direct3D 오브젝트를 찾아서... (8) | 2009/08/17 |
지난 회에서 DXGI 에 대해서 잠깐 살펴보았습니다.
DXGI 에 대한 사용방법은 여기서 언급하지 않습니다.
왜냐하면 제가 진행할 코딩에서는 기본적으로 셋팅되어 있는 그래픽 카드를 사용하는 것을 전제로
진행할 것이기 때문입니다.
혹시 호기심이 더 왕성하신 분들은 IDXGIFactory 인터페이스를 살펴보시면 됩니다.
멤버 함수중에 MakeWindowAssociation, EnumAdapters 정도 살펴보시면 도움이 될 것입니다.
( API 함수 이름만 봐도 느낌이 팍팍! )
예상하시겠지만, DXGI는 연결가능한 장치(어댑터)들을 나열해서
그것 중에 하나 선택하는 역활이 필요합니다.
저는 기본적으로 설정된 어댑터를 사용할 것이기 때문에 이들에 대해서는 언급하지 않겠습니다.
DXGI 계열의 API들도 양이 상당합니다.( 그래서 일단 패스~ )
지난 회에 언급했던 디바이스 초기화를 위한 변수들 기억하시나요?
다시 나열해 보면 아래와 같습니다.
가장 먼저 IDXGISwapChain 에 대해서 살펴봐야하겠지만, 이것에 대한 별도의 설명이 필요할까요?
Front Buffer( 현재 화면에 보여지는 버퍼 )와 Back Buffer( 현재 연산을 해서 기록하는 버퍼 ) 를
준비해서 이것을 Flip 시키면서 번갈아 가면서 보여주는 것을 의미합니다.
( 너무 고전적인 내용이라 더 설명하면 혼날듯...)
우리가 렌더링할 영역(버퍼)에 대한 포맷과 같은 각종 속성들을 설정해 주어서 생성을 요구하고,
포인터를 받으면, 이들 버퍼에 대한 정보를 제어할 수 있습니다.
나중에 살펴보게 되겠지만, Present() 라는 API 를 기억하시나요?
9.0 에서는 이것이 ID3DDevice9의 멤버함수로써 사용했었습니다.
하지만 현재는 IDXGISwapChain 의 멤버함수로 등록되어 잇습니다.
그래서 이에 대한 포인터가 필요합니다.^^
결론적으로 얘기 드리면 앞으로 화면 출력에 관한 모든 것은 IDXGI 계열의 인터페이스로서 제어할 수 있습니다.
< DeviceContext...넌 누구냣!! >
이상한 인터페이스가 DirectX11 에서 생겼습니다.
Device는 무엇인지 알겠는데, DeviceContext 는 또 무엇일까요?
사실 이것은 그동안 Device 인터페이스들이 해오던 역활을 두가지로 분리한 것에 지나지 않습니다.
즉, ID3D11Deivce 는 주로 리소스( 버퍼나 텍스쳐 등 )의 생성에 대한 인터페이스이며,
ID3D11DeviceContext 는 이들 리소스를 제어하고 관리하기 위한 인터페이스입니다.
그렇다면 왜 이렇게 두 가지로 분리된 것일까요?
먼저 아래의 그림을 살펴보겠습니다.
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 작업이 필요없다는 것입니다.
멀티스레드에 안정적이라는 얘기는 스레드 세이프하다는 것입니다.
(정확하게 확신은 아직 드릴 수 없지만, 멀티스레드 관련 렌더링과도 관련이 있는 부분이 여기이지 않을까요.)
사실 리소스의 생성과 해제가 성능에 많은 부분을 차지한다고 볼때,
이렇게 분리되어진 것을 환영해야 할 것입니다.
< 다음 회에는... >
글이 좀 길어지는 것 같아서 일단 여기서 마무리 합니다.
다음 회에는 나머지 초기화 부분에 대해서 계속 언급하겠습니다.^^
| [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 |
| [JumpToDX11-1] 사라진 Direct3D 오브젝트를 찾아서... (8) | 2009/08/17 |
댓글을 달아 주세요