반응형

아마 지금의 자료를 찾지 못했다면 바로 포기했을 것이다.

https://de.slideshare.net/GerkeMaxPreussner/gdc-europe-2014


상당히 유용한 슬라이드였다.

이때 GDC를 갈 기회가 사실 있었는데 왜 안갔을까... GTC가서 물론 재밌게 놀긴(?) 했지만 조금 후회가 된다...


항상 소스코드를 어떻게 어디부터 봐야할지 몰랐는데 디렉터리부터 차근차근 알아가니 좀 진입장벽이 낮아지는 느낌(?)

여하튼 좀 정리를 해본다.



 

아직 보지 않은 부분이기때문에 해당 강의 내용기반으로 정리하는 중이긴 하지만 나중에 하나하나 뜯어보면서 차근차근

틀린 내용에 대해서는 갱신을 하겠다

 

우선 크게 Engine과 Programs 로 나뉘는데

Engine은 모든 code, contents, configurate 등등을 다루고 있는 게임 엔진의 가장 핵심 부분이라 할 수 있다.

Programs는 다양한 프로젝트들이 나열되어 있는것으로 봐서 StandAlone Application들이나 개발 Tool들을 의미한다고 한다.

 

우선 엔진 폴더부터 봐보자.

 

하나씩 폴더 설명부터 정리해 보자면

 

- Build : 엔진부 코드들을 빌딩하는데 필요한 파일들

개발 플랫폼 별로 폴더들이 정리되어있다

 

- Config : Configuation 파일

역시 개발 플랫폼 별로 폴더가 잘 정리가 되어있다. ini파일들을 살펴보면 에디터부터 게임, 하드웨어등 기본 설정값들이 어떤식으로 사용되는지 유추해볼 수 있다.

 

- Content: Shared Engine Context라고 되어있다.

실체가 뭘까 궁금해서 실제로 폴더를 열어보니 에디터에서 유저가 게임 개발에 사용하는 class들이 .template형식으로 저장되어 있다.

 

- Extras: VisualStudioDebugging 이란 폴더가 있고 Visualizer라고 되어있는것으로 유추하여보면 Visual Studio의 Custom Visualizer를 Editor에서 쓰기위해 설정값들이 저장되어있는것으로 추정된다.

 

- Plugins: 게임 Project에 필요한 플러그인으로 Component라고 불러야하나... Editor나 Runtime에서 필요한 기능을 관리하는 폴더라고 보면 될듯하다.

잘 알겠지만 언리얼은 Plug-in형태로 기능을 추가할 수 있다.

 

- Programs: 폴더를 열어보면 빌드툴과 헤더툴이라고 나온다. 언리얼4 빌딩의 자동화를 위한 도구인데 자세한건 다음에 빌드툴 관련해서 작성할때 참고하도록 하자. 생각보다 내용이 정리하기 힘들다...

궁금한 사람들은 https://docs.unrealengine.com/en-us/Programming/BuildTools 참조를 하자.

 

- Shaders: 언리얼 쉐이더 파일들로 확인되고 있고 쉐이더를 만들경우 이 폴더에 두고 작업해야한다.

나중에 리뷰하겠지만 궁금하면 https://www.unrealengine.com/ko/blog/how-to-add-global-shaders-to-ue4 요길 참조하자

 

- Source: 여기가 핵심이다. 메인 소스코드가 전부 있다. 하위 폴더를 잠시 살펴보면 사용가능한 API들을 구현해 놓은 파일들을 가져다 놓았다.

Editor: Unreal 에디터에서 사용할 수 있는 API이다.

Developer: 개발 전용 API로 shader 컴파일러같은것들이 있는걸로 보아 Runtime에서는 사용되지 않을 API들을 의미하는 것 같다

Runtime: 어디서든 사용 가능한 런타임 관련 API들이 있다.

ThirdParty: 언리얼에서 사용하는 Thirdparty lib들에 대한 경로라던가 플랫폼별 세팅들에 대한 C#스크립트와 XML파일이 들어있다.

 

일단은 간단히 여기까지 1-2에서 보도록 하고 1-3에서 본격적으로 하나하나 어떤식으로 파볼지 결정하자.

 

Programs폴더는 다음 기회에 Engine이 어느정도 정리 되면 시작하겠다.

 

폴더에 무엇이 있는지 전혀 알기 힘들었는데 이제 하나하나 보다보니 대충의 언리얼이 얼마나 큰 덩어리였는지 알 수 있게 되었다...

 

과연 Unreal5 이전에 이 분석 작업이 끝날 수 있을까 궁금하다.... 분발해야지...

 

 

 

 




반응형
반응형

언젠가 게임엔진을 만들겠다고 헛소리를 한적이 있었다.

그래서인지 계속해서 언리얼 분석에 대한 욕심만 키우고 있었지 실천에 옮기기가 너무 힘들었다.

 

자... 수십번 다운받았던 소스코드를 위해 이곳으로 가자

 

http://api.unrealengine.com/latest/KOR/GettingStarted/DownloadingUnrealEngine/index.html

 

이곳에서 받자! 예전에 비하면 굉장히 편해졌다!

 

항상 남자라면 마스터 브랜치! 라고 하곤 하지만 사실 공부하는 입장에선 안정적인 릴리즈 브랜치하나 정해서 꾸준하게 정리하는게 좋다.

4.20.3 기준으로 분석을 시작한다. 혹시라도 다루는 릴리즈가 버전이 올라가게 되면 변경사항은 최대한 반영하도록 하겠다!

 

자 git에서 clone 해서 소스코드를 내려받았으면 작업하는 환경이 Windows 이기 때문에 Window개발환경도 적겠다.

빌드용으론 Visual Studio 2017을 사용하고 있고 분석엔 가벼운 Visual Studio Code를 사용하고 있다.

 

위에 소개했던 링크에서 하라는대로 다 하면된다.

 

배치파일(setup.bat) 내부는 몇줄 안되니 분석을 해보자면


echo Engine/Binaries/DotNET/GitDependencies.exe %* >>.git\hooks\post-checkout

 

이 부분으로 봐서  GitDependencies.exe 라는것으로 엔진 툴을 위해 OS 의 dependency를 체크하게 된다.

그리고 해당 git에서 가져오는것을 알수 있다.

꽤 시간이 걸리니 커피 한잔하면서 느긋하게 엔진 파일을 다운받자..

 

 

 

다 다운받으면 


/wait Engine\Extras\Redist\en-us\UE4PrereqSetup_x64.exe /quiet


이부분이 실행되는데 quiet 옵션으로 UI가 안뜨고 조용히 설치가 된다. 아마 엔진구동에 필요한 .net이라던가 dxsdk 등이 깔리는것으로 파악된다.

마지막으로 언리얼 버전을 등록한 후에 setup이 끝난다.


setup이 끝난 후 GenerateProjectFiles.bat파일을 까보면

Engine\Build\BatchFiles 폴더의 GenerateProjectFiles.bat을 실행하라고 나와있는게 보인다.

 

해당 경로의 GenerateProjectFiles.bat 을 까보면 친절하게 주석이 잘 나와있다.

설명을 참조하도록 하자.

이런 배치파일 볼때마다 느끼는거지만 예외처리를 참 주저리주저리(?) 잘 해놓았다.

귀찮지만 꼭 배우고 넘어가야할 점!!!

 

VS2015를 설치하지 않았지만 필자는 다행해 sin파일이 잘 떨어졌으므로 넘어가도록 하겠다.

 

이런거 하나하나 다 적기엔 시간이 없다!!!

 

UE4.sln 을 Visual Studio로 열어보자!

 

설치편은 여기서 마치겠다

 

 

 

반응형
반응형

언리얼 소스 분석란은 순수히 개인적으로 언리얼 스터디를 진행하면서 공부한 내용을 정리하는 것으로 진행합니다.

 

참고로 전혀 언리얼4에 대한 지식 없이 마구 덤벼대는 형식으로 정리하는 것이므로

 

잘 정리되어있는 강좌를 원하시는 분들께 어울리는 내용은 아닐것 같네요.

 

 

그냥 단순하게 언리얼 엔진의 구조를 알고 싶었고,

 

언젠가는 나만의 게임 엔진 개발에 관심이 있습니다.

 

 

이곳에다가라도 정리를 하면서 공부를 진행하는게 나름 효과적일듯하여 시작하는 것입니다.

 

혹시라도 퍼가실 분들은 꼭 (팀) 한너울 블로그의 출처를 달아주시면 감사드리겠습니다!

반응형
반응형

클래스가

static LRESULT CALLBACK 함수명(); 이라는 멤버함수를 가지고 있습니다.

이 정적함수속에서 일반 멤버변수를 호출하였더니,

컴파일시에 비정적멤버를 잘못호출하였다는 에러가 뜹니다.

왜 에러가 뜨는건지. 자세히 설명해 주실 수 있으신지요..

감사합니다.

 

///////////////////////////////////////////////////////////////////////////////////

 

 

정적 함수란 클래스가 존재하지 않아도 호출이 가능한 함수입니다.

그런데 정적 함수 속에서 인스턴스가 생성되지도 않은 개체의 비정적 멤버 함수를 호출했으니

컴파일 에러가 나는건 당연지사입니다.

그런 에러 해결법을 위해서는...

static 멤버 변수로 자기 자신에 대한 포인터를 두거나, 혹은 매개변수로 전달을 받거나..할 수 있겠네요.


class Test
{
public:
........
........
static LRESULT CALLBACK CallBackFunc()
{
if( _This == NULL) _This = new _This;

...
....
return S_OK;
}


private:
static Test* _This;
}


반응형
반응형


 //윈도우 사이즈 계산.
 RECT rc = { startX, startY, wWidth+startX, wHeight+startY };
 AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );

 //윈도우 생성
 m_hWnd = CreateWindow( APP_CLASS_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
   rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance,
  NULL );
 if( !m_hWnd )
 {
  MessageBoxA(NULL, "TestWindow.cpp : Windows handle Error", "HanFW_Error", MB_OK);
  return E_FAIL;
 }

이런식으로 rc에 저장된 사이즈에 AdjustWindowRect을 추가해주면
알아서 제목표시줄, 메뉴등이 포함된 사이즈로 리사이즈된다.
 
나름 초보티는 벗나...라고 생각했는데 이런것도 몰랐다니 나에게 정말 실망이다..

반응형
반응형

RECT rc;
 if(!GetClientRect( hWnd, &rc ))
 {
  MessageBoxA(NULL, "D3D10Device.cpp : Getting window's client size error", "HanFW_Error", MB_OK);
  return E_FAIL;
 }

 //뷰포트사이즈
 vpWidth = rc.right - rc.left;
 vpHeight = rc.bottom - rc.top;

----------------------------------------------------------------------------------
이런식으로 세팅해놓은 윈도우 사이즈의 뷰포트 사이즈를 얻어올 수 있다.
반면 메뉴와 바등의 기타 윈도우 사이즈 통째로 얻어오려면

BOOL GetWindowRect(HWND hWnd, LPRECT lpRect);

이걸 쓰면 된다.
바보같이 일일히 입력하는 수고를 하지 말자...
반응형
반응형

헤더파일에서 private 속성으로 다음과 같이 정의 된 포인터들은
private:
 ID3D10Device *m_pDevice;
 ID3D10Texture2D *m_pDepthStencilBuf;
 ID3D10RenderTargetView *m_pRTView;
 ID3D10DepthStencilView *m_pDepthStencilView;
 IDXGISwapChain *m_pSwapChain;

cpp파일 생성자에서 다음과 같은 방법으로 초기화 해야한다...
CD3D10Device::CD3D10Device(void)
: m_pDevice(NULL)
, m_pDepthStencilBuf(NULL)
, m_pRTView(NULL)
, m_pDepthStencilView(NULL)
, m_pSwapChain(NULL)
{
}

음.. 객체지향들을 때 분명 배웠던건데 왜 까먹은거지....

역시.. 자주 안쓰는 방법이니 까먹은걸지도....
반응형
반응형


헤더파일의 중복 include를 방지 하기 위한 방법!!!!
컴파일러에게 해당 헤더 파일이 한번만 빌드되도록 하는 방법이 있다.

#pragma once
=> 전처리기한테 지시하는 것임.
    한 번 읽으면 다시는 읽지 마라라고 명령한것임

- 사용예 -
#pragma once

어쩌구(예를들면 #include...)

class 어쩌구
{
주저리주저리
}

#ifndef ~ #define ~ #endif 를 이용한 헤더파일 Wrapper 방식보다 쪼끔 더 빠르다 한다.

무조건 헤더파일을 한번 열어서 #ifndef 검사를 한번 해야하기때문이라 한다. 

 

반응형
반응형


유민우
06/11/09 


 


1.DirectX의 역사
엔비디아와 ATI의 차세대 그래픽 칩셋인 G80과 R600의 가장 특징 중 하나는 DirectX 10의 지원이다. 이것 이외에 통합 세이더 아키텍쳐나 물리 연산 지원, 엄청난 하드웨어 사양 등이 있지만, 두 개의 그래픽카드는 모두 DirectX 10 아키텍쳐를 기반으로 설계가 되었다.

 DirectX는 그래픽 API(Application Programmable Interface) 중 하나로, 이 전에는 3dfx의 Voodoo에서 사용하는 Glide 모드와 또 다른 표준으로 OpenGL이 있었다. 이러한 API를 사용하기 전에는 모든 응용프로그램들이 자체적으로 그래픽카드에 대한 드라이버를 제공하였으며, 자신이 사용하는 그래픽카드의 드라이버가 없다면 어디에선가 문제는 발생하기 마련이었다. 이 때에는 윈도우라는 그래픽 유저 인터페이스를 지원하는 운영체제도 없었다. (굳이 언급을 한다면 IBM의 OS/2나 리눅스의 X-Window 정도라고 할까)

 DirectX와 같은 API가 존재하기 전에, 모든 3D 응용프로그램은 그래픽 하드웨어와 직접적으로 드라이버를 통해 통신을 하게 되었다. 이런 직접적인 통신은 매우 빠른 속도를 제공한다는 장점이 있지만, 개발자들 입장에서는 모든 응용프로그램마다 시중에 출시되어 있는 그래픽카드 칩셋에 대한 드라이버를 만들어야 한다는 어려움과 함께 사용자 입장에서도 자신이 사용하는 그래픽카드의 드라이버가 제공되지 않는 응용프로그램은 사용할 수 없다는 불편함이 존재하였다.

 그러던 때에 마이크로소프트는 기존에 Glide 모드와 경쟁을 할 수 있는 DirectX라는 API를 선보인다. 물론 이 때에는 윈도우 95라는 GUI 기반의 운영체제가 있기 때문에 가능한 것이었다. 윈도우95는 모든 드라이버를 운영체제 레벨 하에 관리를 하였기 때문에 응용프로그램들은 운영체제에서 자원만 불러다가 사용하면 되었기 때문에 어느 정도의 인프라는 갖춰졌기 때문이다.

 개발자들은 더 이상 응용프로그램에 맞춰서 3D 응용프로그램을 개발하지 않고 DirectX의 아키텍쳐에 맞는 드라이버를 만들어내고 하드웨어 제조사의 칩셋 개발자 역시 DirectX라는 표준에 맞추기 시작하면서 3D 가속기의 발전은 시작되고 이 때에 엔비디아에서는 NV1이라는 3D 칩셋을 최초로 선보인다. 이 칩셋을 장착한 그래픽카드의 대표 제품은 엣지3D (Edge 3D)라는 당시 30만원이 넘는 고가의 가속기로써 버추어 파이터 1을 번들로 제공하던 그 제품이다.


<3DMark 2001의 Environment Bump Mapping 테스트 장면>

 이후 DirectX는 버전업을 계속함에 따라 DirectX 6에서는 Environment Bump Mapping 이라는 기술이 사용된다. 이 기술은 2D 표면에 굴곡을 넣어 엠보싱처럼 표현해 주는것으로써 물체의 질감을 사실적으로 표현할 때 사용하는 기술이며 매트록스에서 처음으로 자사의 그래픽카드에 EMBM을 추가하였다.

 그리고 DirectX 7이 되면서 T&L (Transform and Lighting)이 CPU에서 그래픽 코어로 넘어옴에 따라 그래픽 코어는 비로소 GPU라는 명칭을 얻을 수 있게 된다. 지오메트리 연산의 일부를 GPU에서 담당함으로써 CPU는 상당한 부담감을 해소할 수 있었고 일부 지오메트리 연산과 A.I. 그리고 물리 연산만을 담당하게 된다. 하드웨어 T&L은 엔비디아의 지포스 256에 처음으로 추가되었다.

[강좌] Transform and Lighting

 DirectX 8. 드디어 세이더라는 개념이 생긴다. 세이더 모델 1.0에 대한 개념이 처음 생기고 프로그래머블 픽셀 세이더 1.0과 버텍스 세이더 1.0이 등장한다. 이때 한 가지 재미있는 사실은 DirectX 8.1에서 엔비디아는 픽셀 세이더 버전 1.3을, ATI는 픽셀 세이더 버전 1.4를 따로 선보였었다.

<3DMark2001 픽셀 세이더 테스트 장면>

 그리고 현재의 DirectX 9는 가장 많은 버전 업이 되면서 세이더 모델 2.0부터 세이더 모델 3.0까지 모두 포함되어 있다.  세이더 모델의 버전이 올라감에 따라 한 번에 처리할 수 있는 명령어의 수도 늘어나게 되었고, 이는 픽셀 세이더 1.0에서 한 번에 12개의 명령어를 처리하던 수준에서 1.3은 28개, 2.0은 96개, 2.0b는 1536개, 3.0은 이런 제한이 사라지게 된다.

 마지막으로 DirectX 10은 ATI에 의해 올해 4월 처음으로 선보였다. 그리고 이 API는 데스크탑이 아니라 콘솔 게임인 Xbox 360에 처음으로 적용되었다. 통합 세이더 아키텍쳐라는 특이한 파이프라인 구조로 되어 있는 이 API가 오늘 강좌의 주인공이다.
 
2.DirectX 9 무엇이 문제인가?
 기존의 DirectX는 그 뼈대는 변하지 않고 여러가지 살만 붙으면서 성장을 하였다. 이는 처음 1.0이 만들어졌을 때 성능보다는 개발자들의 편의와 호환성을 위한 것이었고 성능을 따지기 시작한 것은 T&L을 GPU에서 처리하기 시작한 DirectX 7 때부터이다.

 그러나 이런 DirectX의 고질적인 문제가 있으니 바로 CPU에 과부하를 너무 많이 준다는 것이다. DirectX 자체가 CPU 과부하의 주범이다.


 

 위의 프리젠테이션 자료는 DirectX 10의 설계에 참여한 ATI가 제시한 것으로써, 이를 참조하자면 응용프로그램에서 DirectX 를 호출하고 DX에서는 드라이버를, 드라이버에서는 GPU에 오브젝트를 호출한다. 응용프로그램에서 DX로 오브젝트를 호출 할 때에는 상관이 없지만, DX에서 드라이버로 다시 호출할 때 오버헤드(overhead)가 추가로 붙는다. 문제는 이 오버헤드가 DX를 거칠 때마다 매번 붙는다는 것이다. 이러면 처리 시간이 길어지게 되어 정작 중요한 명령어 처리는 못하고 오버헤드 처리하는데 시간을 낭비하게 된다. 더 큰 문제는 바로 이 과정이 CPU에서 처리한다는 것이다.

 이 오버헤드가 가져오는 문제점은 2가지이다. 한 번에 렌더링할 수 있는 오브젝트 수의 제한과 화면에 보여지는 이펙트의 제한이다. 이런 문제는 개발자들도 잘 알고 있었고 이를 해결하기 위한 방법도 존재한다.

 DirectX 10의 탄생

 DirectX 10의 가장 큰 변화점은 CPU의 간섭을 최소화하고 - CPU에서 담당하는 일을 GPU가 담당 - 기존 DX 8/9에서 나뉘어져 있던 픽셀과 버텍스 세이더 유닛을 하나로 통합했다는 것이다.

 DirectX 10은 윈도우 비스타에 처음으로 사용되어지며 기존 운영체제는 지원을 하지 않는다. 마이크로소프트에서 밝힌 DirectX 9.L은 윈도우XP에서 DirectX 10 호환 그래픽카드를 사용할 수 있도록 해주는 것이 아니라 윈도우 비스타에서 DirectX 9 호한 그래픽카드를 사용할 수 있게 해주는 것이다. 이를 통해서 우리는 한가지 알 수 있다.

 DirectX 10과 기존 DirectX 9는 호환이 안 된다는 점. 호환이 된다면 굳이 DirectX 9.L이라는 또다른 API를 만들어낼 필요가 없이 DirectX 9 호환 그래픽카드를 그냥 DirectX 10을 사용하면 되기 때문이다. 여기에서 호환이라 하면 통합 세이더 아키텍쳐의 사용이다. DX9에서는 통합 세이더 아키텍쳐를 위한 설계가 전혀 되어 있지 않기 때문이다.
 
3.CPU의 부담을 덜어라
 DX10의 지상 과제 중 첫 번째인 CPU로부터의 독립 선언은 CPU의 의존도를 줄이는 것이다. CPU의 의존도를 줄이기 위한 방법 중 하나로 우선은 DX9에서 발생하는 오버헤드를 제거하는 것이다. 이를 위해서 DX10에서는 새로운 런타임 모델을 만들어냈다. DX9에서는 오브젝트를 호출할 때 마다 유효성(Validation)을 확인하는 작업을 하였다. 문제는 이 작업이 한 두 번에 그치는 것이 아니라 수백만 번씩 이루어진 다는 것인데, 이 유효성 작업을 오브젝트의 루프 전에 한 번만 하고 끝낸다는 것이다.

 

<DX9와 DX10의 유효성 루프 성능 차이>

 CPU에서 진행하는 이 작업이 수 백만에서 한 번으로 줄어든 다는 것은 그만큼 CPU의 부담이 줄어든다는 뜻이다.

 이와 함께 CPU의 의존률을 줄이기 위해서 3가지 새로운 기능이 추가된다. 이것들은 각각

texture array
predicated draw
stream out
이라 불리운다.

 Texture array는 최고 512개까지의 텍스쳐를 저장해 놓은 구조체로써, 여기에는 세이더 프로그램이 texture array 내부에서 동적으로 텍스쳐들을 색인할 수 있는 명령어들도 포함되어 있다. Texture array는 GPU에 의해 컨트롤이 되기 때문에 다량의 텍스쳐, 즉 멀티플 텍스쳐를 관리할 때 CPU의 의존도를 줄이게 된다.

 Predicated draw는 겹쳐지는 오브젝트를 처리할 때 사용하는 기능으로써, 앞쪽에 있는 오브젝트에 가려져 있는 뒤쪽의 오브젝트를 렌더링 하기는 하지만 최종적으로 보여지는 이미지에서는 효과를 제외하고 그려내는 것이다. 즉 불필요한 부분까지 세이더 처리를 하기 때문에 그만큼 자원 낭비가 이루어지는 것을 막아낼 수 있다. 이와같은 기법은 현재에도 사용되고 있지만 여전히 처리하지 말아야 할 부분까지 세이딩을 하게 된다. 이런 것을 occlusion query라 불렀으며 DX9 기반에서는 이를 CPU와 GPU가 담당했지만 DX10에서는 오직 GPU에서만 처리를 하게 된다.

 Stream out은 지오메트리 또는 버텍스 세이더의 결과물을 비디오 메모리로 바로 출력하는 새로운 기능이다. 기존에는 버텍스 -> 지오메트리 -> 픽셀 세이더 파이프 라인 순서를 반드시 거쳐야했지만 stream out을 통하면 픽셀 파이프 라인을 거치지 않고 바로 출력이 가능하게 되는 것이다. 이는 DX10의 통합 세이더 아키텍쳐가 있기에 가능한 것이다.

 이런 기능 등을 이용했을 경우 줄어드는 오버헤드의 양은 다음 그래프를 참조하자


 
4.세이더 모델 4.0 (Shader Model 4.0)
DX9에 포함된 세이더 모델 3.0과 DX10에 포함된 세이더 모델 4.0은 구조부터 다르다. DX10에 포함된 세이더 모델 4.0은 통합 세이딩 아키텍쳐(Unified Shading Architecture)라 불리우는 것이 사용되었으며 여기에는 픽셀 세이더, 버텍스 세이더 유닛과 함께 지오메트리 세이더라는 것이 추가되었다. 이로 인해서 세이더 파이프라인은 고정된 것이 아니라 개발자가 직접 프로그래밍할 수 있도록 되어 있다.

 여기에서 세이더 파이프라인의 프로그래밍이란 기존의 프로그래머블 픽셀/버텍스 세이더를 말하는 것이 아니다. 세이더 유닛(스트림 프로세서)의 사용을 프로그래머가 버텍스나 픽셀 세이더로 임의 할당할 수 있다는 뜻이다. 기존에는 하나의 파이프라인에 픽셀/버텍스 세이더 유닛의 수가 고정되어 있었다.

 우선은 세이더 모델 3.0과 세이더 모델 4.0의 차이점을 간단히 표로 정리해 보면,

리소스 DirectX 9 DirectX 10
임시 레지스터  32  4096
고정 레지스터  256  65,536 (16 x 4096)
텍스쳐  16  128
렌더 타겟  4  8
최대 텍스쳐 크기  4096 x 4096  8192 x 8192

 와 같다.

 한 번의 사이클에 처리할 수 있는 텍스쳐의 수가 DX9에서는 16개이지만 DX10에서는 128개로 늘어났으며, 멀티 렌더링 시 동시에 처리할 수 있는 픽셀 세이더의 수도 4개에서 8개로 늘어났다. 또한 텍스쳐의 크기 역시 기존 4096 x 4096에서 최대 4배가 커진 8192 x 8192까지 지원을 한다.

 또한 세이더 모델 4.0에는 새로운 2개의 HDR 포맷이 추가 되었다. DirectX 9에서 사용하던 FP16이나 FP24 이외에 R11G11B10 모드와 R9G9B9+5 모드이다. R11G11B10은 레드와 그린이 각각 11bit씩을 사용하고 B는 10bit를 사용하여 FP32bit로 구성된다. FP16은 3가지 색상을 더해서 16bit가 아니라 하나의 색상에 16bit씩이다. R9G9B9+5의 경우에는 각 색상이 9bit씩을 사용하고 5bit는 공유를 한다.

 DX10의 새로운 모드 2개의 특징이라면 DX9의 FP16이 부동소수점 64bit (RGB 16bit씩 + 알파채널 16bit)에 비해 저장 공간은 절반이면서도 동일한 범위의 다이나믹 레인지를 표현할 수 있다는 것이다.

 그러고 보다 높은 정밀도를 요구하는 HDR의 경우에는 색상 당 32bit에 알바 비트 32bit를 더해서 128bit의 정밀도로 구현을 할 수 있다. 이전 FP16일 경우에는 64bit로 구현이 되었었다.
 
5.통합 세이딩 아키텍쳐 #1
 세이더 모델 4.0에 새롭게 추가된 지오메트리 세이더는 단순히 CPU로부터 데이터를 넘겨받아 이를 처리하기만 하던 수동적인 입장에서 벗어나 직접 데이터를 생성하는 프로세서로써의 역할을 수행할 수 있도록 해주는 결정적인 계기를 제공한다. 기존 세이더 모델 3.0에서는 새로운 데이터를 생성하지는 못하고 오직 외부에서 넘겨 받은 메쉬(mesh)에 픽셀 단위로 세이딩 처리만 하였었다. 그러나 지오메트리 세이더를 탑재함으로써 트라이앵글을 직접 만들어 내는 작업까지 함으로써 CPU의 부담을 대폭 줄여주게 된 것이다.

 이를 통해 실시간 Displacement Mapping, Stencil Shadow Extrusion, 점으로부터 Point-Sprite 생성, Motion Blur 그리고 이외에 많은 효과를 GPU에서 직접 처리할 수 있게 되었다.

 

 <DX10 파이프라인 구조>

  지오메트리 세이더는 버텍스 세이더와 래스터라이저 사이에 위치해 있다. DX10의 파이프라인 구조는 DX9의 파이프라인과는 조금 다르다. DX9까지는 하나의 파이프라인에 버텍스 세이더와 픽셀 세이더가 존재했고 각각의 세이더에는 이를 처리하는 유닛이 있어서 이를 순차적으로 처리하였지만 DX10에서는 처리 순서가 버텍스 세이더->지오메트리 세이더->픽셀 세이더 순서로 처리가 이루어진다.

 여기에서 한가지 특이한 것은 지오메트리 세이더와 래스터라이저 사이에 있는 Stream Output이라는 존재와 가상 비디오 메모리이다. Stream Output은 앞서 설명한 Stream Out 기능을 위해서 매우 중요한 역할을 한다. Stream Output을 통해 다시 Input Assembler로 보내어 지오메트리 데이터를 다시 구성할 수도 있고, 다른 세이더 유닛 그룹과 병렬처리도 가능해진다.
 
6.통합 세이더 아키텍쳐 #2

 

<DX9에서의 세이더 유닛>

<DX10에서의 세이더 유닛>

 DX9의 세이더는 위의 그림에서 보이는 것처럼 세이더의 수가 고정되어 있다. 첫 번째 이미지에 대한 설명을 하자면, 상어를 표현할 때 픽셀 처리보다 버텍스 처리를 많이 하는 것으로 되어 있다. 이럴 때 고정된 세이더의 수는 버텍스 처리 시에 과부하가 걸리는 반면 픽셀 세이더는 활용할 수 있는 만큼 다 사용하지 못하고 아이들 상태로 대기를 한다. 마찬가지로 물을 표현할 때에는 버텍스보다 픽셀 처리를 많이 한다. 이때에는 반대로 픽셀 세이더는 과부하가 걸리는 반면 버텍스 세이더는 100% 활용을 하지 못하게 된다.

 이런 낭비를 막으려면, 프로그래머가 DX9에서 제어 가능한 수의 픽셀/버텍스 세이더를 감안해서 최적화하여 프로그램을 만들면 되지만, 문제는 그래픽카드마다 버텍스와 픽셀 파이프라인의 수가 다르다는데 있다. 기준이 되는 그래픽카드가 없기 때문에 그래픽카드에 따라 성능 차이가 발생한다. 반대로 콘솔 게임의 경우에는 최신 그래픽카드보다 성능이 낮은 그래픽 코어를 사용함에도 불구하고 빠른 성능을 보여준다. 이는 하드웨어의 변경이 없이 하나의 기준에만 맞춰서 게임을 만들어내면 되기 때문이다.

 그렇기 때문에 PC게임->콘솔 게임 또는 콘솔->PC 게임으로의 포팅이 잘 이루어지지 않는 것이다. 하지만 DX10의 경우에는 완벽하지는 않지만 PC와 콘솔 사이의 게임 포팅이 자유롭다. 물론 동일한 API를 사용하는 Xbox 360과 G80 또는 R600 그래픽카드를 사용한다는 전제하에서이다. CPU 부분에서 조금 걸리긴 하지만 그래도 그래픽 처리 부분에서는 상당한 자유도가 부여된다.

 DX10의 파이프라인 구조에서는 버텍스/픽셀/지오메트리 세이더의 수가 고정되어 있지 않고 하드웨어가 허용하는 범위 안에서 자유롭게 사용할 수 있다.
 
7. DX10을 통한 또 다른 게임 세계를 만난다
 DirectX 10은 DirectX 7 이후 성능에 중점을 두고 만들어진 또 다른 구조의 API이다. 버텍스 세이더와 픽셀 세이더를 GPU에서 처리하게 된 DX8에도 성능을 고려하지 않은 것은 아니지만 DX10의 지오메트리 세이더 추가와 통합 세이더 아키텍쳐는 지금까지와는 전혀 다른 구조를 갖고 있기 때문이다.
 Xbox360에는 ATI의 통합 세이더 아키텍쳐가 사용된 1세대 GPU가 포함되어 있다. Xbox 360 사용자들은 잘 알고 있을 것이다. Xbox 360이 제공하는 이미지의 품질을. 그러면서도 전혀 느리다거나 하지는 않다는 것도 말이다. ATI는 데스크탑 최초의 DX10 GPU를 엔비디아에게 내주긴 했지만, Xbox 360 GPU 설계를 통해 얻은 노하우를 바탕으로 2세대 통합 세이더 아키텍쳐를 만들어 R600에 탑재할 것으로 보인다. 비록 엔비디아에 밀리긴 하지만 R600의 파워는 Xbox 360을 뛰어넘을 것으로 보인다.

 DirectX 10가 데스크탑에 적용되는 시점도 얼마 남지 않았다. 윈도우 비스타에 처음으로 탑재될 DirectX 10은 2자리수를 기념하려는 듯 전혀 새로운 아키텍쳐로 다가왔으며, 프로그래머들에게는 편의성을, 일반 사용자에게는 매우 높은 퀄리티의 이미지를 빠르게 볼 수 있도록 해준다.

 필자가 지난 4월에 발표된 DirectX 10을 지금에서야 재정리 해서 올리는 이유는, 이어지는 엔비디아의 지포스 8800GTX 때문이다. 코드명 G80을 GPU를 탑재한 엔비디아의 지포스 8800GTX는 DirectX 10의 아키텍쳐에 호환이 되는 데스크탑 최초의 그래픽카드이다. 또한 내년 1월에 선보이게 될 ATI의 R600에서도 동일하게 적용될 것이기에 앞서 정리를 한 것이다.

  이론상으로는 획기적이기만 한 DirectX10을 지원하는 엔비디아의 지포스 8800GTX. 곧 공개가 되니 기대하기 바란다.
 

[출처] [강좌] 통합 세이더 아키텍쳐로 진화한 DirectX 10|작성자 와우주

문제가 생길경우 삭제하겠습니다.

반응형
반응형

SwapChain에대해서 아직 좀 궁금한게 많아서 이리저리 뒤적거리다
우연히 발견한 내용...


---주의점 (퍼옴)---


1. 기본 device는 첫번째 체인이다.

ex)   pd3dDevice->GetSwapChain(0, &l_pSwpChain1);

2. 추가 창에 swapchain을 적용시킬 경우 체인을 추가시켜준다.

ex)
 ZeroMemory(&l_d3dpp, sizeof(D3DPRESENT_PARAMETERS) );
 D3DDISPLAYMODE mode;
 DXUTGetD3DObject()->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode);

 l_d3dpp.BackBufferWidth = 0;
 l_d3dpp.BackBufferHeight = 0;
 l_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
 l_d3dpp.Windowed = TRUE;
 l_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
 l_d3dpp.BackBufferFormat = mode.Format;
 l_d3dpp.hDeviceWindow = l_cDlgPicView.m_hWnd;
 l_d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

 pd3dDevice->CreateAdditionalSwapChain( &l_d3dpp, &l_pSwpChain2 );


3. 체인을 쓸 경우 기본 체인에도 꼭 백버퍼 설정을 해줘야 한다.

ex)
 LPDIRECT3DSURFACE9 pSurface = NULL;

 pd3dDevice->GetSwapChain(0, &l_pSwpChain1);
 l_pSwpChain1->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pSurface);
 pd3dDevice->SetRenderTarget(0, pSurface);


4. 체인 렌더 시 BeginScene() 과 EndScene() 안에서 실행한다.
   그리고 한 체인의 렌더가 끝났으면 백버퍼를 릴리즈 시킨다.

ex)
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
          ...
          pd3dDevice 를 이용하여 render
          ...

          pSurface->Release();
          pd3dDevice->EndScene();
    }


5. 뷰포트를 얻을 때, 마지막 설정된 디바이스 체인의 뷰포트를 가져온다.

6. SwapChain생성 시 D3DPRESENT_PARAMETERS::SwapEffect 항목으로
   그나마 최적화를 할 수 있다.

ex) D3DSWAPEFFECT_DISCARD, D3DSWAPEFFECT_COPY, D3DSWAPEFFECT_FLIP


7. 서로 전혀 상관되지 않는 무언가를 보여줄 시엔 device를 새로 생성하는 편이 낫다.

ex) 맥스의 분할화면 ( SwapChain ), 텍스쳐 미리보기 창 ( Device 새로 생성 )


8. 이 많은 주의사항을 알려주는 곳이 전무했다.  젠장!
   이라고 원본 글쓴분께서 말하셨다....

반응형

+ Recent posts