Q.
m_pdxgiSwapChain->SetFullscreenState(FALSE, NULL); 무슨 코드?
-
=> 전체 화면 모드 비활성화;
전체 화면모드는 swapchain이 전적으로 관리해서 GPU 리소스 최적화 가능;
==> 창모드는 운영체제에서 렌더링 결과를 관리하기에 VSync 설정이나 프레임 제한이 더 자연스럽게 적용되어 GPU 과부하 줄어들 수 있음.
Q.
swapChain에 알파모드 왜 필요한가?
-
=>
알파값을 변동하는 그래픽 후 처리가 있을 수 있기 떄문;
**출력 일관성을 유지하게 하기 위해서;**
**SwapChain 버퍼와 RTV의 포맷은 동일해야 한다;**
Q.
::ZeroMemory(&dxgiSwapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC1))
-
=> 메모리 블록을 `0x00` 으로 초기화; 내부적으로 `memset`으로 구현
`#define ZeroMemory(Destination, Length) memset((Destination), 0, (Length))`
Q.
::WaitForSingleObject(m_hFenceEvent, INFINITE);
-
=> Windows API에서 제공하는 동기화 함수;
=>이 함수는 특정 객체가 **신호 상태(Signal State)**가 될 때까지 **대기하는 역할**
=> `m_hFenceEvent`:
- 대기할 객체의 핸들로, 보통 이벤트 객체 또는 동기화 기본 객체를 나타냅니다. Direct3D 12에서는 GPU가 명령을 완료했는지 확인하기 위해 페이스(Fence)와 연결된 이벤트 핸들이 자주 사용
Q.
dxgiSwapChainDesc.SampleDesc.Quality = (m_bMsaa4xEnable) ? (m_nMsaa4xQualityLevels - 1) : 0; <- Msaa4x 하면 왜 퀄리티 레벨 1개 낮춤?
-
=> 품질 레벨은 일반적으로 0 부터 시작하기 떄문;
Q.
hResult = ::CreateDXGIFactory2(nDXGIFactoryFlags, __uuidof(IDXGIFactory4), (void
**)&m_pdxgiFactory); <- 왜 IDXGIFactory4인데, Create는 2?
-
=> `CreateDXGIFactory2`는 유지하기 위한 설계로 고정, 반환되는 인터페이스의 버전은 전달된 UUID(`__uuidof(IDXGIFactory4)`)에 따라 달라짐 (4 쓰는 이유는 최신 인터페이스 사용위해)
Q.
Create 할 때, IID_PPV_ARGS 대신 __uuidof(), (void**) 직접 지정
-
=>
특징 |
IID_PPV_ARGS |
__uuidof()와 (void) 직접 지정** |
코드 간결성 |
간결함, 코드 가독성 증가 |
더 많은 코드 작성 필요 |
타입 안정성 |
컴파일 타임에 포인터 타입 불일치 오류를 감지 |
수동으로 타입 관리, 실수할 가능성 존재 |
유연성 |
고정적인 인터페이스 요청 상황에 적합 |
더 많은 커스터마이제이션이 가능 |
디버깅 및 유지보수 |
쉬운 디버깅 및 유지보수 |
코드를 명확히 이해해야 유지보수가 쉬움 |
호환성 |
현대적인 DirectX 및 컴파일러 환경에서 최적화됨 |
오래된 컴파일러와 특수한 환경에서 더 유연하게 작동 가능 |
Q.
void CGameFramework::FrameAdvance()
{
ProcessInput();
AnimateObjects();
HRESULT hResult = m_pd3dCommandAllocator->Reset();
hResult = m_pd3dCommandList->Reset(m_pd3dCommandAllocator, NULL);
여기서 할당자 리셋하면 힙은??, 입력처리 할 떄마다 명령 다 비우기???
-
=> `Reset()`은 Allocator에 기록된 **명령만 초기화**
=> **Command Queue**에 이미 제출된 명령에는 영향을 미치지 않습니다. 즉, GPU가 실행 중인 작업은 안전하게 유지
=> 각 프레임마다 새로운 GPU 명령을 기록하기 위해 기존 명령을 제거 (이 단계의 후면 버퍼는 새로 쓰일 예정)
Q.
void CGameFramework::FrameAdvance() 에서 렌더 타겟 리소스 배리어 왜 2번?
<- 왜 렌더 타겟 2번 렌더링하고 스왑 버퍼 교환??
-
=> 첫번쨰 리소스 배리어는 후면 버퍼를 `제시` ->`렌더링` 상태로 전환 (쓰기모드)
=> 두번째 리소스 배리어는 후면 버퍼를 `렌더링`->`제시` 상태로 전환 (읽기모드)
Q.
D3D12_CPU_DESCRIPTOR_HANDLE d3dDsvCPUDescriptorHandle = m_pd3dDsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); //깊이-스텐실 서술자의 CPU 주소를 계산한다. <- 필요한 이유는?;;;
-
=> CPU 측에서 주소를 바탕으로 서술자 힙에 접근, 특정 힙을 참조하려면(여러 서술자를 관리하는 힙이 ) 시작 주소에서 해당 서술자까지의 오프셋을 계산;
=>`ID3D12DescriptorHeap`는 여러 서술자를 하나의 연속된 메모리 공간에 모아서 관리합니다.
Q.
void CGameTimer::Reset()
{
__int64 nPerformanceCounter;
::QueryPerformanceCounter((LARGE_INTEGER*)&nPerformanceCounter);
m_nLastTime = nPerformanceCounter;
m_nCurrentTime = nPerformanceCounter;
m_bStopped = false;
} <- 이거 왜 퍼포먼스 타이머 지원한다고 가정하고 초기화??
-
=> `timeGetTime()` 함수는 Windows 멀티미디어 타이머 API의 일부로 내부 시스템 타이머 기반이기 Reset이 필요 없기에 성능 카운트 하드웨어 Reset 부분만 존재
Q. 아래 코드 동작의 주의 해야할 부분
```
m_pdxgiSwapChain->Present1(1, 0, &dxgiPresentParameters);
m_pdxgiSwapChain->Present(0, 0);
m_nSwapChainBufferIndex = m_pdxgiSwapChain->GetCurrentBackBufferIndex();
```
-
=> 첫 번쨰 인자는 `0`이면, 수직동기화 비활성; `1`이면 활성. (**근데 적용이 안되는 현상!**) <= 외부 소프트웨어 문제
=> 비정상적인 FPS는 CPU와 GPU가 동기화가 제대로 안 이루어진다는 신호
==> 버퍼 인덱스가 실제 인덱스와 맞지 않으면 동기화가 제대로 안되니, 스왑이 완전히 처리되기 전에 인덱스 전환 X
=> FPS 1000 이상이면 티어링 발생 가능성 높음.