공부중
[DirectX12]Hello Wolrd Sample - D3D12HelloTriangle - 5 본문
// Create synchronization objects and wait until assets have been uploaded to the GPU.
{
ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
m_fenceValue = 1;
// Create an event handle to use for frame synchronization.
m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (m_fenceEvent == nullptr)
{
ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
}
// Wait for the command list to execute; we are reusing the same command
// list in our main loop but for now, we just want to wait for setup to
// complete before continuing.
WaitForPreviousFrame();
}
이번에 정리해볼 코드이다.
동기화 객체를 생성하고 에셋이 GPU에 업로드 될때까지 기다리는 코드이다.
하지만 ..
Fence(울타리)가 어디에 어떻게 쓰이는지 용도를 다시 말하자면
한 시스템에서 두개의 처리장치(CPU와 GPU)가 병렬로 실행되다 보니 여러 동기화 문제가 발생하게 되었고
이를 해결하기 위해서 Fence(울타리)라는 객체를 사용하는것이다.
일단 코드를 차근차근 보자.
ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
m_fenceValue = 1;
device에서 CreateFence를 통해 Fence를 생성해 주고 있다.
그리고 fenceValue라는것을 1로 설정해 주었는데 이 Value는 다음에 설명할 예정이다.
일단 Value라는것이 필요하구나 정도로 넘어가자..
// 프레임 동기화에 사용할 이벤트 핸들을 만듭니다. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); }
Event를 생성하였는데 이것은 프레임 동기화에 사용할 이벤트 핸들이다.
바로 아래의 if문은 만일 생성 실패시에 처리할 코드이다.
// 명령리스트가 실행될 때까지 기다리십시오.
// 우리는 메인 루프에서 같은 명령리스트를 재사용하고 있지만,
// 지금은 계속하기 전에 설치가 완료되기를 기다리고 싶습니다.
WaitForPreviousFrame();
번역은 번역기를 돌렸기 때문에 번역퀄은... -_-;; 신경쓰지 마세요...
아무튼 저 WaitForPreviousFrame함수 안을 살펴 봐야 할것 같다.
void D3D12HelloTriangle::WaitForPreviousFrame()
{
// WAITING FOR THE FRAME TO COMPLETE BEFORE CONTINUING IS NOT BEST PRACTICE.
// This is code implemented as such for simplicity. The D3D12HelloFrameBuffering
// sample illustrates how to use fences for efficient resource usage and to
// maximize GPU utilization.
// Signal and increment the fence value.
const UINT64 fence = m_fenceValue;
ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fence));
m_fenceValue++;
// Wait until the previous frame is finished.
if (m_fence->GetCompletedValue() < fence)
{
ThrowIfFailed(m_fence->SetEventOnCompletion(fence, m_fenceEvent));
WaitForSingleObject(m_fenceEvent, INFINITE);
}
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
}
WaitForPreviousFrame 함수의 내부 이다.
이전 프로젝트와 다른 코드의 내용은 없다.
그런데 망할 과거의 내가 다음 기회에 알아보자고 해서 지금 적어야 겠다 -_-;;(멍청한 과거의 나...)
// Signal and increment the fence value.
const UINT64 fence = m_fenceValue;
ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fence));
m_fenceValue++;
LoadAssets함수에서 m_fenceValue 라는 멤버 변수의 값을 1로 설정을 해두었다.
이 멤버변수의 값을 가져와서 Signal이라는 함수를 호출하는데
MSDN에 적힌 설명을 보면 Updates a fence to a specified value.(Fence를 지정된 값으로 업데이트 한다.) 라고 적혀있다 -_-;;
ID3D12CommandQueue::Signal MSDN 링크
ID3D12CommandQueue::Signal은 GPU측에서 Fence값을 설정하고
ID3D12Fence::Signal은 CPU측에서 Fence값을 설정한다고 한다.
여기서는 ID3D12CommandQueue::Signal이므로 GPU측에서 Fence값을 설정한다.
GPU가 Signal의 명령까지 모든 명령을 처리하기 전까지 새 Fence(울타리)지점은 설정되지 않는다. 라고 그런 결과가 있기는 한데
지금 프로젝트에서는 삼각형 하나 딸랑 띄우는거라 부하걸리는것도 없고해서 -_-;;;
이게 맞는말인지 확인하기가 거시기하다 ... (누군가 알고있으면 알려주세요 ㅠㅠㅠ)
Signal을 호출한 뒤에 멤버변수인 m_fenceValue를 증가 시키고 있다.
// Wait until the previous frame is finished.
if (m_fence->GetCompletedValue() < fence)
{
ThrowIfFailed(m_fence->SetEventOnCompletion(fence, m_fenceEvent));
WaitForSingleObject(m_fenceEvent, INFINITE);
}
ID3D12Fence::GetCompletedValue 함수를 통해서 Fence의 현재 값을 가져오고 위에서 m_fenceValue에서 가져와 상수로 받은 fence 지역변수와 비교를 하고 있다.
if문의 코드는 주석에 적힌대로 이전 프레임이 끝날때까지 기다리는것이다.
이전 프레임이 끝났다면 ID3D12Fence::SetEventOnCompletion를 통해서 울타리가 특정 값에 도달 할 때 발생해야하는 이벤트를 지정해준다.
지정하는 이벤트는 LoadAsset에서 CreateEvent로 만든 m_fenceEvent를 넘겨주고 있다.
다음라인에서는 WaitForSingleObject를 통해서 대기해주고 있다.
WaitForSingleObject는 지정된 객체가 신호를 받거나 제한 시간이 경과 될때까지 대기하는 함수이다.
넘겨주는 시간이 INFINITE(#define INFINITE 0xFFFFFFFF // Infinite timeout)이면 신호를 받을때까지 대기이다.
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
마지막으로 swapChain에서 현재의 BackBuffer의 index를 m_frameIndex 멤버변수에 저장해주고 있다.
이로써 LoadAsset 함수가 모두 끝났고
OnInit 도 끝이 났다.
이전 글에서도 봤다싶이.
Win32Application::Run에서는 변한 코드가 없고 내부의 pSample의 OnInit에 대해서 변한점이 있어서 알아보았당
다음글은 OnUpdate와 OnRender를 알아보고
그리고 혹시나 OnDestory에대해서 알아보면 끝날것 같다.
다음글에서....
'Programing > DirectX' 카테고리의 다른 글
[DirectX12]Hello Wolrd Sample - D3D12HelloTriangle - 7 (shader code) (0) | 2018.05.29 |
---|---|
[DirectX12]Hello Wolrd Sample - D3D12HelloTriangle - 6 (0) | 2018.05.29 |
[DirectX12]Hello Wolrd Sample - D3D12HelloTriangle - 4 (0) | 2018.05.24 |
[DirectX12]Hello Wolrd Sample - D3D12HelloTriangle - 3 (0) | 2018.05.22 |
[DirectX12]Hello Wolrd Sample - D3D12HelloTriangle - 2 (0) | 2018.05.19 |