Direct X 프로그래밍 학습에 대한 조언

간만에 페이스북 DirectX 그룹에 질문이 올라와서 답변을 달았다.
답변 달다보니 몇 가지 강조할 내용은 정리해서 어디 남겨야겠단 생각이 들었다.

DirectX 프로그래밍을 학습하려고 한다면…

1. 현대적인 C++과 달리 모든 DirectX, 그러니까 DirectX 2부터 12까지 모두 포인터를 죽도록 사용하며 아주 능숙하게 사용해야합니다. 포인터 사용에 능숙하지 못하다면 C/C++프로그래밍 기초부터 다시 학습하도록 합니다.

2. DirectX 프로그래밍을 학습하려면 COM에 대한 이해가 필요합니다. 여기서 필요한 COM지식은 C++의 virtual function과 다중상속 개념을 이해하고 실습하는 것과 거의 같습니다. 실제로 in-process COM은 C++의 virtual function과 다중상속 기능을 이용해서 구현되었습니다. 시중의 COM서적들은 불필요하게 방대한 내용을 담고 있으며 DirectX와 같은 in-process COM과 너무 동떨어진 내용을 담고 있습니다. 따라서 COM책을 구해서 본다면 개요 정도만 읽고 넘어갑니다. 그보단 DirectX코드를 사용할때 disassmbly코드를 따라가는 쪽이 훨씬 도움이 많이 됩니다. 혹은 MSDN을 참고하도록 합니다.

3. DirectX 12부터 MS는 샘플코드에 CComPtr클래스 떡칠을 하기 시작했습니다. 자기들은 그게 편할지 모르겠지만 이 망할 캡슐화된 클래스는 동작원리를 감춥니다. 초보자에게는 혼란만 가중시킬 뿐입니다. COM에 대해서 잘 모른다면 CComPtr을 사용해선 안됩니다. 완전히 잘못 사용하게 될뿐더러 뭐가 잘못됐는지 이해하지 못합니다.

4. 3의 연장선상에서 하는 얘긴데 학습단계에서 빌어먹을 wrapper클래스는 가져다 쓰지도 만들어쓰지도 않도록 합니다. raw포인터와 raw api만을 사용합니다.

5. DirectX 9을 사용해봤다면 DirectX 11을 학습하는데 큰 어려움이 없습니다. 그렇다고 처음 시작하면서 9를 먼저 학습할 필요는 없습니다. DirectX 9를 모르고 DirectX 11을 처음 학습한다면 약간 어렵겠지만 큰 문제가 되진 않습니다. 그러니 11부터 시작하도록 합니다.

6. 10과 11은 거의 유사합니다. 10에서 Compute Shader와 멀티 스레드 렌더링 관련 기능이 추가된게 11입니다. 현재 10으로 개발하는 게임은 없고 99%의 Windows및 XBOX게임은 DirectX 11 타겟으로 개발합니다. 그러니 10도 건너뜁니다. 다만 DirectX 10의 샘플 코드는 학습 및 응용에 도움이 됩니다.

7. DirectX 12를 학습하려고 한다면 DirectX 11에 대해 빠싹하게 알고 있어야 합니다. DirectX 11과 12는 완전 다르지만 그래도 11은 기본적으로 알고 있어야 합니다. 11을 알면 도움이 되는 정도가 아니고 11을 모르면 12는 결코 이해하지 못합니다. 첫째로는 12의 API이름과 11의 API이름이 거의 같기 때문이고, 둘째로는 11의 기본적인 사항에서 무엇이 어떤 의도로 어떻게 변경되었는가를 이해해야 12의 프로그래밍이 가능하기 때문입니다. 따라서 11은 필수입니다.

요즘같이 엔진 가져다 쓰는 개발이 대부분인 시대에 DirectX를 학습하려는 사람은 거의 없겠지만 만약 시도하는 이가 있다면 이 글을 읽고 삽질을 덜 하길 바랍니다.


Direct X 프로그래밍 학습에 대한 조언”에 대한 답글 1개

  1. 굉장히 공감하는 글이네요
    특히 4번 같은 경우 물방울책이나 인터넷 11 관련 강좌 시리즈 보면 프레임워크나 wrapper 클래스 바탕으로 진행하는 경우 있어서…차라리 MS쪽 샘플 자료 보면서 맨땅의 헤딩으로 공부헀던 기억이 나네요
    11도 샘플도 12 나올 때쯤인가 후로 나온 것들 보면 comptr 떡칠 되었던 기억도 나고요

    좋아요

  2. 조언 감사드립니다. 그냥 집에 11책이있어 이걸로 공부하고 있는데 하면서도
    9를 건너뛰어도 되는지 12책이 나왔는데 12로 했어야하는것 아닌가 내심 갈등을 했었는데 깔끔하게 정리해주셔서 감사드립니다.

    좋아요

  3. 한달전즈음 2회차로 포프님과 영천님 대화영상을 보니까 ,

    그땐 안들리던 가상함수테이블이 들리더라구요. 면접질문으로 많이 쓰인다고,

    영천님이 정말 관심이 있다면 디스어셈블리로 쫓아가볼것이다 라고 하셨는데

    처음에 전 가상함수테이블을 들었을 때 , 작동과정이 오퍼레이터 함수같이

    부모클래스포인터 변수 에 자식클래스포인터를 대입하면 아마 감춰진 부모클래스멤버 함수포인터 변수의 값이

    자식클래스 함수포인터로 바뀔것이다. 어느정도 말이 된다 생각해서 넘어갔었는데요.(디스어셈블리도 몰랐고 , 볼 줄

    도 몰라서 , 면접에서 저렇게 대답하면 100% 탈락인가요?이건 그냥 자기상상대로

    대답하면 어떻게되는지 알고싶어서 ..)

    오늘에서야 관련 지식글을 보다가 틀렸다는 사실을 알았습니다.(설명글과 그 설명을 디스어셈블리로 도출)

    그래서 의문이 생기는 것 들은 다른데서 찾을게아니라 디스어셈블리를 알면 그 자리에서

    해결이 되겠다 싶더라고요. 이런 신념이 맞는걸까요? 아니 이건 확신하지만

    현재 WIN32API 2D 게임프로그래밍 중반즘 공부하고 있는데 , 게임하나라도 완성해보고

    (조금이나마 더 프로그래밍에 익숙해지고 ) 어셈블리를 공부하는게 좋을까요? 아니면 이제부터라도 곁들여

    공부하는게 좋을까요?

    또 너무나 얕은 지식을 알아가면서도 하다보면 어떤 신념 같은게 생깁니다.

    예를들어 예전엔 “그냥 모든게 숫자고 어떤 문제들을 만나도 숫자로 생각하면 해결되는구나” 라거나,

    vector 에 배열을 동적할당 하고 카운트가 다 차면 , 두배의 배열을 할당해서 카피하고 기존의배열은 메모리해제

    하는걸로봐서 컴퓨터도 너무나 물리적인,물리적(인스탄스)으로 돌아가는구나 ,

    현재 map 이나 vector , list를 사용하고 있어서 조금씩

    와닿고있는 조건문과 반복문이면 된다라는 포프님영상제목을보고 나중에 저 신념으로 바뀌겠구나

    생각하고 있습니다.

    문제인지 궁금한 부분은 항상 지금껏 생각하고 거기서 기억나는 신념들을 여럿 떠올리며 그 신념을 기반으로

    코딩하려고 하는 것 입니다.(코딩을 하기가 심플해져서 수월해지는 “기분”때문에, 착각인지 모르지만)

    이런경험이 있으셔서 그렇게하면안된다 라던지,

    아니면 어떤 신념같은게 있으신지 궁금합니다.

    좋아요

    1. 면접에 vtable을 물어봤는데 대답을 잘못했다…라고 하면 그것 때문에 떨어질거라고는 생각하지 않습니다. 보통 면접관 입장에서 여러 질문을 던지고 그 중 하나 대답 못했다고 바로 떨어뜨리진 않거든요.
      하지만 vtable질문을 포함해서 대부분 대답을 잘 못했다면 떨어지겠죠. 저라면 vtable 질문에 좋은 답변을 했다면 그것만으로도 높은 점수를 줄겁니다. 그런데 그거 하나 대답 못했다고 바로 떨어뜨릴것 같지는 않네요.

      어셈블리 코드에 대해서 말씀을 드리자면, 결국 일을 제대로 하려하면 어셈블리 코드 안볼수가 없게 됩니다. 디버깅도 디버깅이지만 소스코드만으로는 원리가 이해되지 않을때가 많죠. 이럴때 어셈블리 코드로 따라가보면 원리를 이해할 수 있습니다. 전 디버깅할때디스어셈블창을 많이 들여다봅니다만, 그보다도 원리를 알고 싶을때, 예를 들면 exception의 동작원리( https://megayuchi.com/2017/12/14/c-exception의-내부-구현에-대한-잡설/ )라든가 SRWLock의 동작원리(https://megayuchi.com/2017/06/25/srwlock-빠른-성능의-비결/) 라든가 궁금할때 디스어셈블된 코드를 봅니다.

      신념이라고 하기엔 좀 어울리지 않는것 같고요. C/C++에서 어떤 기능을 사용해도 얘네들은 네이티브 코드이기 때문에 어셈블리로 할 수 있는거보다 더 할 수 있는건 없습니다. 따라서 STL이든 C++ 20의 새로운 기능이건간에 디스어셈블리 코드로 따라가보면 원리는 다 이해할 수 있고 같은 기능을 스스로 만들수도 있습니다. 그래서 네이티브 언어의 새로운 기능에 대해선 전 별로 관심이 없는 편이고요. 두려움도 없습니다. 엄청 마법같은 기능은 처음부터 존재할수 없거든요.

      어셈블리어를 학습해야하는가? 라고 하면 책보고 예제 써가면서 일부러 학습할 필요는 없다고 생각합니다.
      예전에 제가 페이스북에 적은 글이 있네요. 이거 참고하시면 될것 같습니다.

      효과적인 어셈블리어 학습방법.

      1. Visual Studio의 disassembly창을항상 띄워둔다.

      2. 함수의 일부를 inline 어셈블리어로 작성한다. 가령 a+b를 리턴하는 함수를 작성한다면 C언어로 작성해놓고 c= a+b 만 어셈블리코드로 바꾼다.

      2. 인라인 어셈블리를 사용하되 naked call을 이용해서 스택 프레임을 직접 구성한다. epilogue, prologue를 직접 어셈으로 작성한다. 이 시점에서 네이티브 어셈블리 코드와 사실상 똑같다.

      3. masm으로 함수 하나씩을 짠다. 인라인 어셈은 32비트로 제한되지만 여기서부터 x64도 가능. 커맨드라인에서 어셈블 할 필요없다. .asm파일을 VS로 드래그앤드롭하면 ml64또는 masm으로 빌드하도록 설정을 자동으로 다 맞춰준다. .asm파일에 브레이크 포인트 찍어서 디버깅도 할 수 있다.

      4. 모르는건 웹검색을 해도 되지만 VS의 디스어셈블 창을 보는게 대체로 더 효과적이다. 가령 FPU사용법을 모르겠다..그러면 32비트 모드에서 float연산을 해보고 디스어셈블 창을 확인하면 된다. 디스어셈블 창에 나온 명령어가 뭔지 모르겠으면 구글검색하면 된다.

      5. 어차피 유저모드에서 하드웨어를 직접 건드리는 명령은 사용불가능하므로 이 정도 학습이면 유저모드에서 어셈블리어를 사용하기엔 충분하다.
      프로텍티드 모드로 진입하거나 MMU를 제어하거나 in/out port를 사용하는건 다른 학습이 필요하다.

      15년쯤 전에 잡지 강좌로 내보냈던 글인데 이것도 참고하시고요.
      http://yuchi.asuscomm.com/xe/Programming_QA/5950

      좋아요

      1. C/C++에서 어떤 기능을 사용해도 얘네들은 네이티브 코드이기 때문에 어셈블리로 할 수 있는거보다 더 할 수 있는건 없습니다. 따라서 STL이든 C++ 20의 새로운 기능이건간에 디스어셈블리 코드로 따라가보면 원리는 다 이해할 수 있고 같은 기능을 스스로 만들수도 있습니다. 그래서 네이티브 언어의 새로운 기능에 대해선 전 별로 관심이 없는 편이고요. 두려움도 없습니다. 엄청 마법같은 기능은 처음부터 존재할수 없거든요.

        // 이부분이 평소 공상만 하던걸 긁어주는 부분이었습니다. 네이티브 코드는 어셈블리와 1:1대응이라 같은기능을
        스스로 만들수있다.

        지금 당장 인라인함수(강의영상으로 배웠지만 가상테이블처럼 당시에 아리송해서,,)
        도 정확히 몰라 이해는 무리지만 참고할만한 글들과 링크를 해주셔서 감사합니다.

        질문이 다시 생각하니 뭔가 어떤 신념으로 문제를 해결하면 그걸믿고 간단히 해결하고싶은마음에서 비롯된것
        같습니다.

        좋아요

  4. 이 좋은 글을 이제 봅니다. 매번 영천님 유튜브만보다가 호기심이 생겨서 directx12 책사서 공부하는 고등학생입니다..책에서는 ComPtr을 거의 스마트 포인터 개념으로만 생각하라고해서 무시하고 썼었는데.. directx11부터 배워야할 것을 이제라도 알아서 다행입니다. 포인터는 ID3D12 *m_device
    처럼 쓰시라는거죠? 은어에 약해서….아무쪼록 정말 감사합니당 ㅎㅎ

    좋아요

      1. 저.. 영천님 ComPtr의 Reset()은 어떻게 구현해야할까요?
        그리구 구현하기 위해 알아야 될 개념은 뭐가있을까요…

        좋아요

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중