https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

대략적인 가닥은 잡혔는데 핵심적인 부분의 방식을 아직 구상하지 못하고 있습니다.

우선 대략적인 부분.

입력된 무어 머신을 앞에서부터 순회합니다.

그리고 Spells Vector와 Index Vector로 나누어서 관리합니다.

Spells는 무어머신에 입력된 Alphabat. 즉 State의 저장입니다.

중복된 알파뱃이 입력될 수 있으므로 이를 따로 관리하기 위해 Vector로 관리를 합니다.

 

그리고 이 State들간의 관계. 즉 Condition을 최대한 가볍게 구현하기 위해 Vector<Vector<int>>를 추가했습니다.

이 Vector는 Index값으로 State들간의 관계를 나타냅니다.

선행 State와 후행 State가 일대다 관계도, 다대일 관계도 가능하기에
어쩔 수 없이 이차원 Vector를 사용해야 할 것 같습니다.

 

무어 머신을 순회하면서 Alphabat이 들어오면 기본적으로 선행 Alphabat의 Index Vector에 값이 추가됩니다.

단, Alphabat이 아닌 특수 문자가 들어올 때에는 특수한 작업이 발생합니다.

이 때 문제가 발생합니다.

 

) 문자가 들어온 이후의 첫 Alphabat은 선행 State들과 연결을 지어야 합니다.

이것이 가능하려면 선행 Alphabat이 어디부터 어디까지인지 판단을 할 수 있어야 합니다.

그런데 이를 판단하는 방식을 아직 구상하지 못했습니다.

 

우선은 height Vector를 먼저 도입해볼까 합니다.

현재 Alphabat과 인접한 Alphabat과 같은 Height를 지닌 연속적인 모든 Alphabat을

선행 Alphabat으로 판정하는 것입니다.

 

그 이후에 형성된 그래프를 순회하는 것도 고민을 해봐야 할 것 같습니다.

오늘은 크게 무언가를 하지는 않고 간단하게 구현만 조금 했습니다.

우선 어제 새벽에 작성한 내용들을 담을 수 있는 Interface를 새로 선언했습니다.

가능하면 함수 선언도 해두려고 했으나 기능 구현에 대해
포괄적으로 적용 할 수 있는 형태를 아직 확립하지 못해 몇몇 부분을 보류하고 있습니다.

 

그리고 일전에 선언 해두었던 InRangeCharacter와 IObjectActivity Interface를 ActorBase와 Character에 적용하였습니다.

아무래도 내용이 많다보니 이 부분이 의외로 시간을 꽤 잡아먹었습니다.

 

마지막으로 Melee Attack의 판정을 개선했습니다.

Notify 발생 위치를 조절하고,
왼손 오른손을 햇갈려 했던 것을 명확히 하여 수정한 결과 비교적 만족스럽게 작동하고 있습니다.

 

가능하면 FSM을 관리하는 Sequential Interface도 미리 선언해두고 싶으나, 시간이 오래 걸릴 것 같습니다.

저번처럼 밤에 생각이 나면 맞춰보겠지만, 우선은 후순위로 미뤄두려고 합니다.

일단은 CheckAnswer 부분을 구현을 해볼까 합니다.

현재 생각나는 것은 물건 부착, 피격, Widget에 텍스트 입력을 생각하고 있습니다.

 

그 다음에는 Climb 기능을 먼저 구현하고자 합니다.

Trap보다는 아무래도 이미 완성된 기능들이다 보니 Climb를 먼저 정리하는 편이 더 적절하다고 생각합니다.

하면서 생각이 뚫리면 장애물을 넘어가는 기능도 조심스래 건드려볼 계획입니다.

 

그 다음에 Trap을 구현하고, Puzzle을 제작해보려 합니다.

'개발일지 > Treasure Hunter' 카테고리의 다른 글

20.07.30 개발일지  (0) 2020.07.30
20.07.29 개발일지  (0) 2020.07.29
20.07.26 개발일지  (0) 2020.07.26
20.07.23 개발일지  (0) 2020.07.23
20.07.22 개발일지  (0) 2020.07.22

https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

이전에 짰던 코드가 입력되는 String에 반복적인 알파뱃이 존재 할 때
Shift 과정에서 오류가 발생한다는 점을 깨달았습니다.

더 큰 문제는 추가적인 복잡한 구조나 대량의 메모리가 없이는 개선을 할 수 없다는 점이었습니다.

 

그래서 구조를 다시 짜보고 있습니다.

처음에는 struct를 이용한 Graph를 이용해보려 했습니다.

runtime 상에서 메모리를 잡는 거은 큰 부하가 걸리므로 Stack Object들로 관리를 하였습니다.

하지만 Graph라고 해도 Directed Graph라서 흐름을 역행하는 케이스를 검색하는 것에 문제가 발생하였습니다.

 

현재는 여기까지 개발을 한 상태입니다.

그리고 일지를 적다가 Graph를 Array로 표현하는 방법을 떠올렸습니다.

입력된 Machine에서 모든 State를 Vector에 순차적을로 담고,
각 State가 어떤 State로 갈 수 있는지 index 값을 Vector로 담고 있는 방식입니다.

 

여기서 문제가 될 수 있는 부분은 두가지입니다.

하나는 하향식이든 상향식이든 일대 다 관계가 발생할 수 있다는 점.

다른 하나는 State가 많아질수록 기하급수적으로 Graph 정보가 많아진다는 점입니다.

 

우선은 이 구현하던 것을 지우고 Array 식으로 변경해서 새로 구현을 해보려 합니다.

아무래도 Vector보다는 부하가 적을 것 같아서입니다.

조금 조급해져 주말에 개발하려다가 지원을 고민하는 회사에 지원하기로 마음 먹어 야밤에 글을 씁니다.

 

Trap과 Puzzle의 관계에 대해서 고민을 해보았습니다.

 

제가 개발하는 게임 내에서

Trap이란 유저의 진행을 방해하는 모든 장치들을 지칭합니다.

단순히 텔레포트, 총알 발사, 몬스터 소환, 방해물 설치서부터 시작해 여러 장치들이 복잡하게 발동되기도 합니다.

 

Puzzle이란 유저의 행동으로 해제가 가능한 모든 장치들을 지칭합니다.

Puzzle은 대체로 Trap을 동반하지만, 단순한 입력도 게임 내에서는 Puzzle로 취급됩니다.

 

Trap은 여러 Trap이 복합적으로 발동되더라도 기본적으로 각각의 Trap의 발동 조건이 변하지 않습니다.

하지만 Puzzle이 지니고 있는 Trap은 발동 조건이 바뀔 수도 있습니다.

예를 들어, 범위 안에 플레이어가 존재해야 발동하는 Trap의 경우,
Puzzle에 붙으면 그 범위가 Puzzle의 범위에서 발동해야 할 수도 있습니다.

이전 구조에서도 이 문제를 고민하면서 변경을 꾀했는데 현재 이에 대해 두가지 방안을 고민 중입니다.

 

1. 이 문제는 모든 Trap과 Puzzle의 SuperClass인 THActorBase가 태생적으로 Area를 지니고 있기 때문이다.

그러니 Puzzle에서 Trap들의 Area를 자신의 Area와 동일하게 지정하여
동일한 이벤트가 발생하는 대상을 Trap의 Area에서 Puzzle의 Area로 바꾸어 보려 합니다. 

이 방법의 가장 큰 장점은 나중에 기획을 하면서

Multiple Trap에서 Trap의 발동 범위가 바뀌는 경우에도 문제 없이 적용이 가능하다는 점입니다.

단점? 아니 문제점은 정상적으로 작동할지 아직 모릅니다.

 

2. Puzzle이 가지고 있는 Trap의 이벤트 함수를 모두 지운 뒤, 자체적으로 생성해서 다시 배정하는 방식입니다.

이는 구조 변경 전에도 동일하게 적용될 수 있는 방법이라 1번 방안에 비해 비교적 적절치 못하다고 생각합니다.

 

Trap과 Puzzle의 관계를 배정하면서 몇가지 추가되어야 하는 Interface가 있습니다.

첫번째로, FSM을 관리하는 Interface가 필요합니다.

여러 Trap들이 발동 할 때, 순차적으로 발동한다는 보장이 없습니다.

지름길이 있을 수도 있고, 실패 시 다른 Sequence로 움직여야 할 수 있습니다.

그리고 이러한 흐름을 관리하려면 FSM이 필요할 것이라 봅니다.

더불어서 FSM을 효과적으로 표현할 수 있는 자료구조 방식도 구상해야 합니다.

 

두번째로, CheckAnswer Interface를 다시 되살려야 합니다.

Puzzle의 복합적인 작동을 고려하다 보니 Check Answer 과정도 유일하다고 볼 수 없습니다.

때문에 Check Answer를 하는 Object를 종류별로 제작하고, Puzzle이 상황에 맞게 1개 이상 소유하도록 하려 합니다.

 

우선은 각 Interface들을 제작하고, Trap에 적용을 한 뒤 Trap과 Puzzle을 더 기획하려 합니다.

가능하면 Check Answer Object을 3가지 정도 만들고, Trap과 조합하여 여러 종류의 Puzzle을 생성해보려 합니다.

'개발일지 > Treasure Hunter' 카테고리의 다른 글

20.07.29 개발일지  (0) 2020.07.29
20.07.27 개발일지  (0) 2020.07.27
20.07.23 개발일지  (0) 2020.07.23
20.07.22 개발일지  (0) 2020.07.22
20.07.20 개발일지  (0) 2020.07.20

오늘은 코드를 보고 원하는 방향대로 어느정도 수정을 해보고 있습니다.

그런데 워낙에 양이 방대하여 그대로 작성하는 것만 해도 하루 종일 했음에도 시간이 부족했습니다.

https://github.com/d3dcoder/d3d12book/tree/master/Common

 

d3dcoder/d3d12book

Sample code for the book "Introduction to 3D Game Programming with DirectX 12" - d3dcoder/d3d12book

github.com

책의 예시에서는 예시 별 다른 Proejct를 지원하고 있습니다.

또한 공통 함수인 D3DApp을 상속받은 각 코드 안에서 WINMAIN이 작동되고 있습니다.

제가 하고자 하는 일은 이를 각 Class 단위로 분리하고,
Window 상에서 메뉴의 버튼 클릭을 통해 각 예시들을 교체 할 수 있도록 하는 것입니다.

여러 확장 코드들이 있지만 우선은 예시 코드를 보고 가능하면 이를 사용하지 않고 구현 중입니다.

 

공부 하면서 자체 엔진을 게발하는 회사들도 엄청나게 많은 기반 코드를 작성 해놓을 것만 같았습니다.

'내용정리 > DirectX12' 카테고리의 다른 글

20.07.31 개발일지  (0) 2020.07.31
20.07.28 개발일지  (0) 2020.07.28
20.07.24 일지  (0) 2020.07.24
08. Direct3D의 초기화 - CPU와 GPU의 상호작용  (0) 2020.07.24
08. Direct3D의 초기화 - 기본지식 2  (0) 2020.07.24

화요일에 면접 본 곳에 혹시나 하고 사이트를 들어가봤더니 불합격이 떠 있었습니다.

이로서 이번 하반기에 모든 회사에 다 떨어졌습니다.

마지막 면접 본 회사는 기대를 하지는 않았습니다.

유니티를 쓰는데 저는 유니티와 C#은 무난하게 사용할 수 있을 정도로만 알고 있기 때문입니다.

면접을 ㅈ박았으니 떨어질거라고 마음을 다지고 있었지만

막상 떨어지니 이 병신 머저리는 5년간 대학 다니면서 뭘 했길래 2년 가까이 취직도 못하고 있나 싶습니다.

 

면접 때 말실수 한것, 아는 내용이었음에도 머리가 하얗게 지워져 대답하지 못한 것. 그럼에도 허세만 부린것.

그것보다 더 견디기 힘든것은

누구보다 학부생 때 더 노력을 했다고 자부 함에도 현실이 시궁창이라는 것.

난 도대체 얼마나 못났길래 남들과 같이 되려면 지금보다 더 많은 시간과 노력이 필요한 것인가.

이제 내가 할 수 있는 일이라고는 이것 밖에 없는데 왜 이마저도 더럽게 못하는가.

언제까지 용돈이나 축내면서 지내야 하는가.

하루하루 공부랍시고 키보드를 두들기고 있지만 머리와 마음은 이미 바스라져 버린 것 같고

불과 2년 전까지만 해도 학교에서 개발을 했을 때 어땠는지 기억이 나지 않는다.

 

이대로 게임업계는 커녕 개발자 흉내도 못내고 전전긍긍하다가 혼자 말라 비틀어질 것 같다.

그냥 누가 알려줬으면 좋겠다.

내가 지금 뭘 해야 하는지.

난 지금 뭐가 부족한지.

당사에 들어가려면 뭘 해야 하는지.

 

면접관 발바닥이라도 핥아서라도 회사에 들어가고 싶은 심정이다.

울고 싶어도 눈물 조차 안나온다.

잘하고 싶다. 누구보다 잘 하고 싶고, 게임을 만들고 싶다.

근데 아무도 나를 찾아주지 않는다.

누가 나좀 살려줬으면 좋겠다.

'일기장' 카테고리의 다른 글

분야 별로 요구하는 포트폴리오 포맷이 다른가봅니다.  (0) 2020.08.11
갑자기 면접 제의가 쏟아지네요  (0) 2020.08.06
면접을 다시 한번 망쳤습니다  (0) 2020.08.05
20.04.22  (0) 2020.04.23
20.04.21  (0) 2020.04.21

https://www.acmicpc.net/problem/3300

 

3300번: 무어 기계

문제 무어 기계는 상태에 의해서 출력이 결정되는 유한 상태 기계이다. 무어 기계는 이름은 미국의 수학자이자 컴퓨터 과학자 Edward F. Moore의 이름을 따서 지었다. 무어 기계의 상태 전이는 입력�

www.acmicpc.net

예시는 다 통과가 될 정도로 수정을 하고 제출을 해보았는데 런타임 에러가 발생했습니다.

몇가지 예시를 종이에 더 적어보았는데 이걸 확대해서 테스트 해봐야겠습니다.

썩 마음에 드는 코드 방식도 아닌데 이게 문제가 생기니까 막막합니다.

이거 언제 또 고치지...

예전에는 내용 정리와 일지랑 섞어서 쓰긴 했는데 좀 분리를 해볼까 합니다.

어차피 내용 정리는 나중에 옮겨야 겠지만.

 

현재 4-3까지 읽었고, 5챕터를 읽은 상태입니다.

이제 여기서 선택지가 있어 조금 고민입니다.

 

하나는 4-4를 읽으면서 구조를 직접 짜보고 나중에 수정하는 것.

다른 하나는 5챕터 예시 코드를 보면서 우선 코드를 작성해놓고, 남은 4챕터와 6챕터를 읽고 코드 정리를 하는 것입니다.

 

아마 직접 해보는 전자가 더 정확히 익힐 수도 있겠지만,
잘 모르는건 예시를 우선 보는 것이 더 잘 이해하기에 후자로 진행하고자 합니다.

 

그래서 당장 다음 공부 날짜인 내일은 6챕터 코드를 제가 원하는 형태로 바꿔가면서 작성을 하려고 합니다.

아마 하루에 끝날 것 같지는 않은데, 이게 끝나면 4챕터 남은 것, 6챕터를 읽으면서 주석을 상세히 작성하고자 합니다.

'내용정리 > DirectX12' 카테고리의 다른 글

20.07.28 개발일지  (0) 2020.07.28
20.07.25 개발일지  (0) 2020.07.25
08. Direct3D의 초기화 - CPU와 GPU의 상호작용  (0) 2020.07.24
08. Direct3D의 초기화 - 기본지식 2  (0) 2020.07.24
09. 렌더링 파이프라인 2  (1) 2020.07.14
  • Graphic Programming에서는 GPU와 CPU. 두 Processor가 작동한다는 점을 이해할 필요가 있다.

  • 이 둘은 병렬로 작동하지만, 종종 동기화가 필요하다.

  • 최적의 성능을 위해서는 둘 모두 최대한 바쁘게 돌아가게 만들어야 하며, 동기화를 최소화 해야 한다.

    • 동기화는 한 Processor의 작업이 마칠 때까지 다른 Processor는 놀아야 한다는 것을 의미한다.

  • 한마디로, 동기화는 병렬성을 망친다.

명렬 대기열(Command Queue)과 명령 목록(Command List)

  • CPU는  Command List를 Direct3D API를 통해 GPU의 Command Queue에 제출한다.

    • 하지만 "Queue"에서 알 수 있듯이,
      Command Queue에 넘어갔다고 GPU가 그 즉시 실행하는 것은 아니다.

    • Command들은 GPU가 처리할 준비가 되어야 비로서 실행되기 시작한다.

    • 즉, GPU가 이전에 제출된 Command를 처리하는 동안에는 Queue에 남아 있다는 것이다.

  • Command Queue가 비면 GPU는 놀게 되고, 꽉 차면 Queue에 자리가 생길 때까지 CPU가 놀게 된다.

    • 게임 같은 High-Quality Application에서는 가용 Hardware Resource를 최대한 쓰는 것이 목표다.

    • 즉, CPU도 GPU도 항상 쉬지 않고 일하게 만들어야 한다.

  • Direct3D 12에서 Command Queue를 담당하는 Interface는 ID3D12CommandQueue이다.

    • 이를 생성하기 위해서는 D3D12_COMMAND_QUEUE_DESC 구조체를 채운 후 ID3D12Device::CreateCommandQueue를 호출해야 한다.

  • 다음은 Command Queue를 채우는 방식을 보여주는 예시 코드이다.

Microsoft::WRL::ComPtr<ID3D12CommandQueue> mCommandQueue;
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Flags = D3D12_COMNAND_QUEUE_FLAG_NONE;
ThrowIfFailed(md3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)));
  • 위 예시 코드에서 사용된 보조 메크로 IID_PPV_ARGS는 다음과 같이 정의되어 있다.

#define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType)
  • 여기서 __uuidof(**(ppType))은 (**(ppType))의 COM Interface ID로 평가 된다.

    • 위 예에서의 ID는 ID3D12CommandQueue이다.

  • 보조함수 IID_PPV_ARGS_Helper는 ppType을 void**로 Cast한다.

  • Direct3D 12 API에는 생성하고자 하는 Interface의 COM ID와 void**를 받는 함수들이 많기 때문에

    책에서 이 매크로를 선언하고, 책 내의 예시코드 전반적으로 사용되고 있다.

ExcuteCommandLists

  • ExcuteCommandLists는 Command List에 있는 Command들을 Queue에 추가하는 메서드이다.

void ID3D12CommandQueue::ExecuteCommandLists(
  UINT              NumCommandLists,
  ID3D12CommandList * const *ppCommandLists
);

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12commandqueue-executecommandlists

 

ID3D12CommandQueue::ExecuteCommandLists (d3d12.h) - Win32 apps

Submits an array of command lists for execution.

docs.microsoft.com

  • 선언으로 보면 ID3D12CommandList가 Command List를 담당하는 것 같지만,

    실제 그래픽 작업을 위한 Command List는 이를 상속하는 ID3D12GraphicsCommandList라는 Interface가 담당한다.

HRESULT Close();

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12graphicscommandlist-close

 

ID3D12GraphicsCommandList::Close (d3d12.h) - Win32 apps

Indicates that recording to the command list has finished.

docs.microsoft.com

  • ExcuteCommandLists로 Command List를 제출하기 전에

    반드시 이 메서드를 이용해 Command List를 닫아야 함을 기억하자.

CreateCommandAllocator

  • Command List에는 ID3D12CommandAllocator가 하나 연관된다.

    • Command List에 추가된 Command들은 이 Allocator의 메모리에 저장된다.

  • ExcuteCommandLists로 Command List를 제출하면 Command Queue는 Allocator에 담긴 Command들을 참조한다.

  • Command Memory Allocator는 다음 메서드를 이용해 생성한다.

HRESULT CreateCommandAllocator(
  D3D12_COMMAND_LIST_TYPE type,
  REFIID                  riid,
  void                    **ppCommandAllocator
);

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createcommandallocator

 

ID3D12Device::CreateCommandAllocator (d3d12.h) - Win32 apps

Creates a command allocator object.

docs.microsoft.com

  • type은 이 Allocator와 연관시킬 수 있는 Command List 종류이다.

  • 책에서 주로 쓰이는 Type은 다음과 같다.

D3D12_COMMAND_LIST_TYPE_DIRECT

  • GPU가 직접 실행 시킬 수 있는 Command List

  • 지금까지 설명한 Command List들이 이에 포함됨.

D3D12_COMMAND_LIST_TYPE_BUNDLE

  • Bundle을 나타내는 Command List

  • Command List를 만드는 데에 CPU의 부담이 어느정도 따른다.

    • 때문에 Direct3D 12는 일련의 Command들을 Bundle 단위로 기록할 수 있는 최적화 수단을 제공한다.

  • Bundle을 추가하면 Driver는 Rendering 도중에 실행이 최적화 되도록 Bundle의 Command들을 PreCompile한다.

  • Application이 특정 Command List들을 구축하는데 시간이 오래 걸린다면, 이를 고려할 필요가 있다.

    • 단, Direct3D 12 API는 이미 아주 효율적이라 이런 경우가 자주 생기지 않는다.

    • 때문에 Bundle 사용이 성능상 이득을 가져오는 명백한 경우에만 사용한다.

  • 즉, Bundle을 무조건 사용하지는 말아야 한다.

riid

  • 생성하고자 하는 ID3D12CommandAllocator의 COM ID

ppCommandAllocator

  • 생성된 Command Allocator를 가리키는 포인터

  • 출력되는 매개변수

typedef enum D3D12_COMMAND_LIST_TYPE {
  D3D12_COMMAND_LIST_TYPE_DIRECT,
  D3D12_COMMAND_LIST_TYPE_BUNDLE,
  D3D12_COMMAND_LIST_TYPE_COMPUTE,
  D3D12_COMMAND_LIST_TYPE_COPY,
  D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE,
  D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
  D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE
} ;

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createcommandallocator

 

ID3D12Device::CreateCommandAllocator (d3d12.h) - Win32 apps

Creates a command allocator object.

docs.microsoft.com

CreateCommandList

HRESULT ID3D12Device::CreateCommandList(
  UINT                    nodeMask,
  D3D12_COMMAND_LIST_TYPE type,
  ID3D12CommandAllocator  *pCommandAllocator,
  ID3D12PipelineState     *pInitialState,
  REFIID                  riid,
  void                    **ppCommandList
);

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createcommandlist

 

ID3D12Device::CreateCommandList - Win32 apps

Creates a command list.

docs.microsoft.com

nodeMask

  • GPU가 여러개일 때에는 이 Command List와 연관시킬

    물리적 GPU Adpater Node들을 지정하는 비트마스크 값을 설정한다.

  • GPU가 하나인 겨우에는 0으로 설정하면 된다.

  • System의 GPU Adapter node 개수는 다음 메서드로 알아낼 수 있다.

UINT ID3D12DeviceGetNodeCount();

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-getnodecount

 

ID3D12Device::GetNodeCount (d3d12.h) - Win32 apps

Reports the number of physical adapters (nodes) that are associated with this device.

docs.microsoft.com

type

  • Command List의 종류

  • pCommandAllocator

    • 생성된 Command List와 연관시킬 Allocator

    • Command Allocator의 type은 Command List의 type와 일치해야 한다.

pInitialState

  • Command List의 초기 Pipeline 상태를 지정한다.

  • Bundle이거나 초기화 목적으로 쓰이고 실제 그리기 명령이 없는 Command List의 경우 null을 지정한다.

  • 자세한 내용은 나중에 추가로 정리 할 예정이다.

riid

  • 생성하고자 하는 Command List에 해당하는 ID3D12CommandList Interface의 COM ID

ppCommandList

  • 생성된 Command List를 가르키는 포인터

  • 출력 매개변수

  • 한 Allocator를 여러 Command List에 연관시켜도 되지만,
    Command를 여러 Command List에 동시에 기록할 수는 없다.

    • 바꿔 말하면, 현재 Command를 추가하는 Command List를 제외한 모든 Command List들은 닫혀 있어야 한다.

    • 그래야 Command List의 모든 Command가 Allocator 안에 인접해서 저장된다.

  • Command List를 Create 하거나 Reset하면 Command List가 열린 상태가 된다.

    • 때문에 같은 Allocator로 두 Command List를 연달아 Create하면 오류가 발생한다.

Reset

HRESULT ID3D12GraphicsCommandList::Reset(
  ID3D12CommandAllocator *pAllocator,
  ID3D12PipelineState    *pInitialState
);

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12graphicscommandlist-reset

 

ID3D12GraphicsCommandList::Reset (d3d12.h) - Win32 apps

Resets a command list back to its initial state as if a new command list was just created.

docs.microsoft.com

  • Reset 함수는 Command List뿐만 아니라 Command Allocator에서도 제공한다.

    • 예를 들어, 하나의 Frame을 완성하는데 필요한 Rendering 명령들을 모두 GPU에 제출 한 후에는

      Command Allocator의 Memory를 다음 Frame을 위해 재사용해야 할 것이다.

    • ID3D12CommandAllocator::Reset 메서드는 이 때 사용된다.

HRESULT ID3D12CommandAllocator::Reset();

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12commandallocator-reset

 

ID3D12CommandAllocator::Reset (d3d12.h) - Win32 apps

Indicates to re-use the memory that is associated with the command allocator.

docs.microsoft.com

  • 하지만 Command Queue가 Allocator 안의 자료를 참조하고 있을수도 있다.

    • 때문에 GPU가 Command Allocator에 담긴 모든 Command를 실행했음이 확실해지기 전까지
      Command Allocator를 재설정하지 말아야 한다.

CPU/GPU 동기화

  • 한 System에서 두 개의 Processor가 병렬로 실행되다 보니 여러 동기화문제가 발생한다.

    • 이에 대한 해결법 중 하나는 GPU가 Command Queue의 Command들 중

      특정 지점까지의 모든 Command를 다 처리할 때까지 CPU를 기다리게 하는 것이다.

  • Queue의 모든 Command를 처리하는 것을 Flush라고 한다.

  • 이 때 필요한 것은 Fence라는 객체이다.

    • Fence는 ID3D12Fence Interface로 구현하며 GPU와 CPU의 동기화를 위한 수단으로 쓰인다.

    • Fence를 생성하는 메서드는 다음과 같다.

HRESULT ID3D12Device::CreateFence(
  UINT64            InitialValue,
  D3D12_FENCE_FLAGS Flags,
  REFIID            riid,
  void              **ppFence
);

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-createfence

 

ID3D12Device::CreateFence (d3d12.h) - Win32 apps

Creates a fence object.

docs.microsoft.com

  • Fence 객체는 UINT64 값 하나를 관리한다.

    • 이는 그냥 시간상의 특정 Fence 지점을 식별하는 정수이다.

  • 예를 들어, Fence가 하나도 없을 때에는 이 값을 0으로 둔다.

    • 새 Fence를 만들 때에는 이 값이 1씩 증가한다.

  • 이를 아래 예시 코드를 보며 더 자세히 설명을 해보겠다.

UINT64 mCurrentFence = 0;
void D3DApp::FlushCommandQueue()
{
	// 현재 Fence 지점까지의 명령들을 표시하도록 Fence 값을 전진시킨다.
    mCurrentFence++;
    
    // 새 Fence 지점을 설정하는 Signal을 Command Queue에 추가한다.
    // 지금 우리는 GPU timeline상에 있으므로 새 Fence 지점은 
    // GPU가 이 Signal() Command까지의 모든 명령을 처리하기 전까지는 설정되지 않는다.
    ThrowIfFailed(mCommandQueue->Signal(mFence.Get(), mCurrentFence));
    
    // GPU가 이 Fence 지점까지의 Command들을 완료할 때까지 기다린다.
    if(mFence->GetCompletedValue() < mCurrentFence)
    {
    	HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
        
        // GPU가 현재 Fence 지점에 도달했으면 이벤트를 발동한다.
        ThrowIfFailed(mFence->SetEventOnCompletion(mCurrentFence, eventHandle));
        
        // GPU가 현재 Fence 지점에 도달했음을 뜻하는 이벤트를 기다린다.
        WaitForSingleObject(eventHandle, INFINITE);
        CloseHandle(eventHandle);
    }
}
  • 하지만 이것은 이상적인 해결책은 아니다.

    • GPU의 작업이 끝날 때까지 CPU가 기다려야하기 때문이다.

  • 하지만 충분히 간단한 해결책이므로 당분간은 이 방법을 이용한다.

  • Command Queue를 비우는 시점에는 제약이 거의 없다.

    • 특히 한 Frame에서 1번만 비워야 하는 것도 아니다.

  • 예를 들어 초기화를 위한 GPU Command들이 있다고 하자.

    • 먼저 그 Command가 실행되었음이 확실해진 후 Command Allocator를 재설정 하려면

      Command Queue를 비운 후 Command Allocator를 Reset하면 된다.

  • Resource hazard를 막기 위해 Direct3D는 Resource들에게 State를 부여한다.

    • 새로 생성된 Resource는 Default State로 시작한다.

  • 임의의 State Transition를 Direct3D에게 보고하는 것은 전적으로 Application의 몫이다.

    • 덕분에 GPU는 State를 전이하고 Resourece Hazard를 방지하는데 필요한 일들을 자유롭게 진행할 수 있다.

  • 예를 들어, Texture Resource에 자료를 기록해야 할 때에는 그 Texture의 State를 Render Object State로 설정한다.

    • 이후 Texture의 자료를 읽어야 할 때가 되면 State를 Shader Resource State로 Transition 한다.

  • Application이 State Transition을 Direct3D에게 보고 함으로써,
    GPU는 Resource Hazard를 피하는데 필요한 조치를 할 수 있다.

    • 쓰기 연산이 완료되길 기다린 후 읽기를 시도 하는 등

  • Resource Transition을 보고하는 부담을 Application이 담당하는 것은 성능 때문이다.

    • GPU 입장에서는 Transition이 언제 발생하는지 몰라 항상 자동으로 추적하게 해야 한다.

    • Programmer는 이러한 Transition이 언제 일어아는지 미리 알고 있기에 필요할 때 추적할 수 있다.

전이 자원 장벽(Transition Resource Barrier)

  • Resource State Transition은 Transition Resource Barrier들의 Array를 설정해서 지정한다.

    • Array를한번의 API 호출로 여러 개의 Resource를 Transition 할 수 있다.

  • 코드 상에서는 Resource Barrier는 D3D12_RESOURCE_DESC 구조체로 서술된다.

typedef struct D3D12_RESOURCE_BARRIER {
  D3D12_RESOURCE_BARRIER_TYPE  Type;
  D3D12_RESOURCE_BARRIER_FLAGS Flags;
  union {
    D3D12_RESOURCE_TRANSITION_BARRIER Transition;
    D3D12_RESOURCE_ALIASING_BARRIER   Aliasing;
    D3D12_RESOURCE_UAV_BARRIER        UAV;
  };
} D3D12_RESOURCE_BARRIER;

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_resource_barrier

 

D3D12_RESOURCE_BARRIER (d3d12.h) - Win32 apps

Describes a resource barrier (transition in resource use).

docs.microsoft.com

  • 이 책에서는 Direct3D 12의 구조체들에 여러 편의용 메서드들을 추가한 확장 버전을 사용한다.

    • 대부분의 구조체들은 이런 편의용 확장 버전들이 존재하며,
      이 책에서 사용하는 것들은 Microsoft 사이트에서 내려받을 수 있다.

https://docs.microsoft.com/en-us/windows/win32/direct3d12/helper-structures-for-d3d12

 

Helper Structures for D3D12 - Win32 apps

These helper structures help initialize many of the Direct3D 12 structures, and are declared in d3dx12.h.

docs.microsoft.com

https://github.com/microsoft/DirectX-Graphics-Samples

 

microsoft/DirectX-Graphics-Samples

This repo contains the DirectX Graphics samples that demonstrate how to build graphics intensive applications on Windows. - microsoft/DirectX-Graphics-Samples

github.com

  • Transition Resource Barrier는 GPU에게 Resource의 State가 Transition됨을 알려주는
    하나의 Command라고 생각할 수 있다.

    • Comand를 통해 Resource State Transition를 알려주는 덕분에,
      GPU는 이후 Command들을 실행 할 때 Resource Hazard를 피하는데 필요한 단계를 밟을 수 있다.

Command List를 이용한 Multi Thread 활용

  • Direct3D 12는 Multi Thread를 효율적으로 활용할 수 있도록 설계되었다.

    • Command List의 서러계는 Direct3D가 Multi Thread 적용의 장점을 취하는 대표적인 한 방법이다.

  • 물체가 많은 큰 장면을 다룰 때,
    장면 전체를 하나의 Command List로 그리려 하면 구축하는데 CPU 시간이 오래 걸린다.

    • 이에 대한 자명한 해결책은 여러 개의 Command List를 병렬로 구축하는 것이다.

  • Command List 구축에 Multi Thread를 적용 할 때 주의해야 할 점이 쳐가지 있다.

    1. Command List와 Command Allocator는 Free-Threaded 하지 않는다.

      보통의 경우 여러 Thread가 같은 Command List나 Allocator를 공유하지도 않고,
      그 메서드들을 동시에 호출하지도 않는다.

      따라서, 일반적으로 각 Thread는 각자 자신만의 Command List와 Allocator를 가지게 된다.

    2. Command Queue는 Free-Threaded하다.

      즉, 여러 Thread가 같은 Command Queue에 접근해서 그 메서드들을 동시에 호출할 수 있다.

      특히, Thread들이 각자 생성한 Command List를 동시에 Command Queue에 제출할 수 있다.

    3. 성능상의 이유로,
      Application은 동시에 기록할 수 있는
      Command List의 최대 개수를 반드시 초기화 시점에서 설정해야 한다.

  • 단순함을 위해, 이 책에서는 Multi Thread를 사용하지 않는다.

    • 하지만 System Resource 사용을 극대화 하려면 Application이

      반드시 Multi Thread를 이용해 Multi Core의 장점을 최대한 활용할 필요가 있다.

'내용정리 > DirectX12' 카테고리의 다른 글

20.07.25 개발일지  (0) 2020.07.25
20.07.24 일지  (0) 2020.07.24
08. Direct3D의 초기화 - 기본지식 2  (0) 2020.07.24
09. 렌더링 파이프라인 2  (1) 2020.07.14
09. 렌더링 파이프라인 1  (0) 2020.07.14

이전 내용은 DirectX11 기반 내용을 현재 DirectX12에 맞게 검색한 뒤 작성한 내용입니다.

이후 DirectX12 책을 구매하였고, 몇가지 내용이 추가되어 그 내용을 우선 작성합니다.

 

---------------------------------------------------------------------------------------------------

 

DXGI(DirectX Graphics Infrastructure)

  • DirectX3D와 함께 쓰이는 API로 여러 그래픽 API들에 공통인 그래픽 관련 작업들이 존재한다.

    • 예를 들어 SwapChain을 위한 대표적인 Interface인 IDXGISwapShain은 사실 DXGI API일부이다.

    • 그 밖에 Graphic System Data의 Enumeration. 그리고 지원되는 표현 형식들도 DXGI가 제공한다.

IDXGIFactory

  • 주로 IDXGISwapChain Interface 생성과 Display Adapter Enumeration에 쓰인다.

IDXGIAdapter

  • Display Adapter를 대표하는 Interface

Display Adapter

  • 그래픽 기능성을 구현하며, 일반적으로 하드웨어 장치(ex. Graphic Card)이다.

    • 하지만 하드웨어 그래픽 기능성을 흉내내는 소프트웨어 디스플레이 기능성도 존재한다.

  • 하나의 시스템은 여러개의 Adpater를 가질 수 있다.

IDXGIOutput

  • Display Output을 담당하는 Interface.

  • DXGI_MODE_DESC 구조체에는 하나의 Display Mode를 서술하는 여러 멤버들이 있다.

typedef struct DXGI_MODE_DESC {
  UINT                     Width;
  UINT                     Height;
  DXGI_RATIONAL            RefreshRate;
  DXGI_FORMAT              Format;
  DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
  DXGI_MODE_SCALING        Scaling;
} DXGI_MODE_DESC;

typedef struct DXGI_RATIONAL {
  UINT Numerator;
  UINT Denominator;
} DXGI_RATIONAL;

typedef enum DXGI_MODE_SCANLINE_ORDER { 
  DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED        = 0,
  DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE        = 1,
  DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST  = 2,
  DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST  = 3
} DXGI_MODE_SCANLINE_ORDER;

typedef enum DXGI_MODE_SCALING { 
  DXGI_MODE_SCALING_UNSPECIFIED  = 0,
  DXGI_MODE_SCALING_CENTERED     = 1,
  DXGI_MODE_SCALING_STRETCHED    = 2
} DXGI_MODE_SCALING;

https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/bb173064(v=vs.85)

 

DXGI_MODE_DESC structure (Windows)

DXGI_MODE_DESC structure 05/18/2018 2 minutes to read In this article --> Describes a display mode. Syntax typedef struct DXGI_MODE_DESC { UINT                     Width; UINT                     Height; DXGI_RATIONA

docs.microsoft.com

  • 이러한 Display Mode Enumeration은 전체 화면 모드로 갈 때 특히 중요하다.

    • 성능을 극대화 하려면 지정된 Display Mode가 반드시 모니터가 지원하는 Display Mode와 일치해야 한다.

    • 모니터가 지원하는 Display Mode들을 열거해 그 중 하나를 지정하면 이러한 일치성이 보장된다.

Display Output

  • 모니터와 같이 화면을 출력하는 장치.

기능 지원 점검

  • ID3D12Device::CheckFeatureSupport 메서드는 Graphic Driver의 MultiSampling 지원 여부를

    점검할 수 있다고 소개했다.

    • 하지만 이는 CheckFeatureSupport가 확인할 수 있는 수 많은 기능들 중 하나일 뿐이다.

  • CheckFeatureSupport의 서명은 다음과 같다.

HRESULT CheckFeatureSupport(
  D3D12_FEATURE Feature,
  void          *pFeatureSupportData,
  UINT          FeatureSupportDataSize
);
  • Feature는 이 메서드로 지원 여부를 점검할 기능들의 종류를 나타낸다.

  • pFeatureSupportData는 기능 지원 정보가 설정될 구조체를 가르키는 포인터이다.

    • 이는 Feature 값에 따라 구체적인 형식이 다르다.

  • FeatureSupportDataSize는 pFeatureSupportData에 전달한 구조체의 크기를 나타낸다.

D3D12_FEATURE_D3D12_OPTIONS

  • Direct3D 12의 여러 기능들을 점검한다.

  • pFeatureSupportData에는 D3D12_FEATURE_DATA_D3D12_OPTIONS 인스턴스를 가르키는 포인터를 넣어야 한다.

DED12_FEATURE_ARCHITECTURE

  • Hardware Architecture 기능들을 점검한다.

  • pFeatureSupportData에 D3D12_FEATURE_DATA_ARCHITECTURE 인스턴스를 가르키는 포인터를 넣어야 한다.

D3D12_FEATURE_FEATURE_LEVELS

  • 기능 수준들을 점검한다.

  • D3D12_FEATURE_DATA_FEATURE_LEVELS 인스턴스를 가리키는 포인터를 넣어야 한다.

D3D12_FEATURE_FORMAT_SUPPORT

  • 주어진 Texture 형식에 대한 기능들을 점검한다.

  • D3D12_FEATURE_DATA_FORMAT_SUPPORT 인스턴스를 가르키는 포인터를 넣어야 한다.

D3D12_FEATURE_MULTICAMPLE_QUALITY_LEVELS

  • MultiSampling 기능들을 점검한다.

  • D3D12_FEATURE_DATA_MULTISAMPLING_QUALITY_LEVELS 인스턴스를 가르키는 포인터를 넣어야 한다.

상주성(Residency)

  • 게임에 사용되는 모든 자원이 GPU를 필요로 하는 것은 아니다.

  • 때문에 Direct3D 12의 Application은 Resource를 GPU 메모리로부터 내리거나 올려서
    Residency를 관리한다.

    • 이러한 작업의 핵심은 GPU Memory 점유율을 최소화 하는 것이다.

  • 성능적 측면에서 한가지 주의해야 할 점이 있다.

    • Application은 같은 자원을 짧은 시간에 GPU Memory에 넣었다 뺐다 하는 상황을 피해야 한다.

    • 이러한 활동에는 비용이 따르기 때문이다.

  • 이상적으로, 한동안 사용하지 않는 Resource들만 GPU Memory에서 내려야 한다.

  • Residency을 변경하는 대표적인 예로는 Level이나 Area가 바뀌는 시점을 들 수 있다.

  • 보통은 Resource를 생성하면 GPU Memory에 올라가고, 파괴되면 Memory에서 내려간다.

    • 하지만 다음 메서드들을 이용해 Application이 직접 Residency를 제어할 수 있다.

HRESULT ID3D12Device::MakeResident(
  UINT           NumObjects,
  ID3D12Pageable * const *ppObjects
);

HRESULT ID3D12Device::Evict(
  UINT           NumObjects,
  ID3D12Pageable * const *ppObjects
);

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-makeresident

 

ID3D12Device::MakeResident (d3d12.h) - Win32 apps

Makes objects resident for the device.

docs.microsoft.com

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-evict

 

ID3D12Device::Evict (d3d12.h) - Win32 apps

Enables the page-out of data, which precludes GPU access of that data.

docs.microsoft.com

 

+ Recent posts