공부중

[DirectX12]Hello Wolrd Sample - D3D12HelloWindow - 8 본문

Programing/DirectX

[DirectX12]Hello Wolrd Sample - D3D12HelloWindow - 8

곤란 2018. 5. 13. 20:15
반응형

 

LRESULT CALLBACK Win32Application::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	DXSample* pSample = reinterpret_cast<DXSample*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));

	switch (message)
	{
	case WM_CREATE:
		{
			// Save the DXSample* passed in to CreateWindow.
			LPCREATESTRUCT pCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
			SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pCreateStruct->lpCreateParams));
		}
		return 0;

	case WM_KEYDOWN:
		if (pSample)
		{
			pSample->OnKeyDown(static_cast<UINT8>(wParam));
		}
		return 0;

	case WM_KEYUP:
		if (pSample)
		{
			pSample->OnKeyUp(static_cast<UINT8>(wParam));
		}
		return 0;

	case WM_PAINT:
		if (pSample)
		{
			pSample->OnUpdate();
			pSample->OnRender();
		}
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	// Handle any messages the switch statement didn't.
	return DefWindowProc(hWnd, message, wParam, lParam);
}

 

신기하기는 하지만 위와같이 WM_PAINT에 update와 render가 돌고 있었다.

 

간단히 말하자면 Update는 로직을, Render는 그리는것을 담당한다고 생각하면 된다.

 

먼저 OnUpdate를 보자..

 

void D3D12HelloWindow::OnUpdate()
{
}

 

창만 띄우므로 OnUpdate에서는 해줄것이 없다.

 

 

void D3D12HelloWindow::OnRender()
{
	// 장면을 렌더링 하는데 필요한 모든 명령을 기록
	PopulateCommandList();

	// 명령 리스트 실행.
	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

	// 프레임 전환
	ThrowIfFailed(m_swapChain->Present(1, 0));

	WaitForPreviousFrame();
}

PopulateCommandList라는 D3D12HelloWindow의 멤버함수를 먼저 호출하고

명령 리스트를 실행한뒤에

프레임 전환을 하고

WaitForPreviouisFrame이라는 멤버함수를 호출해 주고 있다.

 

위에서부터 순차적으로 보자.

void D3D12HelloWindow::PopulateCommandList()
{
	/*
		명령리스트 할당자(Command List Allocatiors)는 관련 명령리스트가 
		GPU에서 실행을 완료 한 경우에만 재설정 될 수 있습니다.
		앱은 Fence(울타리)를 사용하여 GPU 실행 진행 상황을 확인해야 한다.
	*/
	ThrowIfFailed(m_commandAllocator->Reset());

	/*
		ExecuteCommandList()가 특정 목록에서 호출되면 
		해당 명령 목록을 언제든지 다시 설정할 수 있으며 다시 기록 해야한다.
	*/
	ThrowIfFailed(m_commandList->Reset(m_commandAllocator.Get(), m_pipelineState.Get()));

	// 백버퍼(back buffer)가 렌더링 대상으로 사용될 것임을 나타낸다.
	m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get()
										,D3D12_RESOURCE_STATE_PRESENT
										,D3D12_RESOURCE_STATE_RENDER_TARGET));

	CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()
						, m_frameIndex
						, m_rtvDescriptorSize);

	// 명령 기록.
	const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f }; //컬러값.
        //RTV(Render Target View)정리. - 위에서 받아온 핸들과 위에서 적은 컬러
	m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);	값.

	// 백버퍼(back buffer)가 현재 사용되는 것을 나타낸다. -> 백버퍼에 기록한것을 화면으로 전환.(back buffer -> front buffer)
	m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get()
										,D3D12_RESOURCE_STATE_RENDER_TARGET
										,D3D12_RESOURCE_STATE_PRESENT));

	// 명령 닫기.
	ThrowIfFailed(m_commandList->Close());
}

m_commandAllocator->Reset() 은 명령 할당 자와 연관된 메모리를 다시 사용함을 나타낸다.

(m_commandAllocator는 ID3D12CommandAllocator 형이다.)

 

m_commandList->Reset()은 새 명령리스트가 방금 생성 된 것처럼 명령리스트를 초기 상태로 재설정한다.

(m_commandList는 ID3D12GraphicsCommandList 형이다.)

 

그 후에 m_commandList->ResourceBarrier를 통해서 리소스에 대한 다중 액세스를 동기화해야한다는 것을 드라이버에 알린다.

 

리소스를 무분별하게 사용하게되는(GPU가 리소스에 데이터를 다 기록하지 않았거나 아직 시작하지도 않은 상태에서 리소스 데이터를 읽으려고할때) 부분을 막기 위해서 리소스에 상태(state)를 부여하게 되는데. 임의의 상태 전이를 Direct3D에게 알려줌으로써 자원위험상황(resource hazard)를 막아준다. 이 상태 전이를 알려주기 위해서 전이자원장벽(transition resource barrier)을 이용한다.

 

자원 장벽은 D3D12_RESOURCE_BARRIER_DESC구조체로 서술되고 주석에 적혀있듯이 CD3DX12_RESOURCE_BARRIER의 Transition을 통해서 백버퍼가 렌더링 대상으로 사용될 것을 나타내주는 코드이다.(CD3DX12_RESOURCE_BARRIER는 D3D12_RESOURCE_BARRIER_DESC를 상속 받는다)

PRESENT -> RENDER_TARGET

 

rtvHandle을 생성해주고 배경색(?)을 지정해주는 코드가 보인다.

후에 ClearRanderTargetView를 통해서 위에서 지정해준 컬러 값으로 RTV를 칠해주고

마지막으로 백버퍼가 렌더링 대상으로 사용될 것을 나타내줬던 코드처럼 백버퍼에 기록한 것을 화면으로 전환해주는 코드이다.

RENDER_TARGET -> PRESENT

 

명령들을 모두 기록 끝냈으므로 Close로 닫아준다.

 

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

 

다음글에서

반응형