D3D12엔진개발- Render Target의 Post Processing

d3d12_normal_blur_outline

가로 세로 7샘플씩, x축으로 한번, y축으로 한번씩 blur를 먹이는 blur filter를 구현했다.
laplacian filter를 적용해서 outline을 검출하는 필터도 구현했다.
D3D9나 D3D11에선 별것도 아닌 기능이지만 D3D12에서 구현하는건 그리 간단하지는 않았다.

예를 들어 BLUR를 보자.

Original Image -> Resize -> Blur X -> Blur Y

이 순서로 가야하는데 D3D12이전에는

Original Image ->  Resize – (wait for complete) ->  Blur X – (wait for complete) -> Blur Y – (wait for complete)

이렇게 진행된다. constant buffer를 재활용할 수있다. 그냥 순서대로 함수를 나열하면 된다.

 

D3D12에선

Original Image ->  Resize ->  Blur X -> Blur Y – (wait for complete)

이렇게 진행된다. 각 단계에서 필요한 Constant Buffer는 모든 단계가 완료될때까지 불변을 보장해야한다. 또한 렌더링에 사용될 DescriptorTable도 미리 각 단계만큼 만들어두던가 아니면 하나를 생성하고 단계별로 붙여서 세팅해야한다. 렌더링할때마다 옵셋을 건너뛰면서 말이다.

Resize, Blur X, Blur Y이렇게 3단계가 있으므로 디스크립터 테이블은 다음과 같이 구성한다. 디스크립터는 9개가 필요하다.

|CBV | SRV0 | SRV1 | – | CBV | SRV0 | SRV1 | – | CBV | SRV0 | SRV1 |

3개씩 묶어서 Descriptor Table로 전달한다.

코드로 보면 다음과 같다. CRenderTexture는 Texture Resoruce를 두개씩 갖고 있다. 외부에서 입력된 Texture srvSrc를 Resize -> Blur X -> Blur Y 처리해서 자신의 Texture Resource 0번에 저장한다.

BOOL CRenderTexture::ApplyEffectBlur(D3D12_CPU_DESCRIPTOR_HANDLE srvSrc,DWORD dwSrcWidth,DWORD dwSrcHeight)
{
	ID3D12Device*				pDevice = m_pRenderer->INL_GetD3DDevice();
	ID3D12GraphicsCommandList*	pCommandList =  m_pRenderer->INL_GetCommandList(COMMAND_LIST_TYPE_DEFAULT);

	CONSTANT_BUFFER_POST_EFFECT*	pConstantBuffer = (CONSTANT_BUFFER_POST_EFFECT*)m_pCbvDataBegin;
	
	CD3DX12_CPU_DESCRIPTOR_HANDLE	rtv0(m_pRTVHeap->GetCPUDescriptorHandleForHeapStart(),0,m_rtvDescriptorSize);
	CD3DX12_CPU_DESCRIPTOR_HANDLE	srv0(m_pSRVHeap->GetCPUDescriptorHandleForHeapStart(),0,m_commonDescriptorSize);

	CD3DX12_CPU_DESCRIPTOR_HANDLE	rtv1(m_pRTVHeap->GetCPUDescriptorHandleForHeapStart(),1,m_rtvDescriptorSize);
	CD3DX12_CPU_DESCRIPTOR_HANDLE	srv1(m_pSRVHeap->GetCPUDescriptorHandleForHeapStart(),1,m_commonDescriptorSize);

	CD3DX12_CPU_DESCRIPTOR_HANDLE	srvDest0(m_pCommonHeap->GetCPUDescriptorHandleForHeapStart(),1,m_commonDescriptorSize);	// srv 0

	// set constant buffer
	SetOffset9Sample(pConstantBuffer,dwSrcWidth,dwSrcHeight);	// for bartlette blur
	SetOffset7Sample(pConstantBuffer,m_Width,m_Height);			// for x-y blur

	pConstantBuffer->v4AdjSrcTex.x = 1.0f / (float)dwSrcWidth;
	pConstantBuffer->v4AdjSrcTex.y = 1.0f / (float)dwSrcHeight;

	pCommandList->RSSetViewports(1,&m_vp);	
	pCommandList->RSSetScissorRects(1,&m_scissorRect);

	ID3D12DescriptorHeap* ppHeaps[] = { m_pCommonHeap };
	pCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
	pCommandList->SetGraphicsRootSignature(m_pRootSignature);

		
	pCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
	pCommandList->IASetVertexBuffers(0, 1, &m_VertexBufferView);

	// pass 1, Resize with Bartlette filter
	CD3DX12_GPU_DESCRIPTOR_HANDLE	commonHeapHandle(m_pCommonHeap->GetGPUDescriptorHandleForHeapStart());
	pCommandList->SetGraphicsRootDescriptorTable(0,commonHeapHandle);	// CBV : Default | SRV : srcSrv
	
	pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_ppRenderTarget[0], D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET));
	pCommandList->OMSetRenderTargets(1,&rtv0,FALSE,NULL);

	// set srv0 with source texture
	pDevice->CopyDescriptorsSimple(1,srvDest0,srvSrc,D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
	
	pCommandList->SetPipelineState(m_pPipelineState[POST_PROCESS_TYPE_BLUR_BARTLETTE]);
	pCommandList->DrawInstanced(4,1,0,0);
	
	pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_ppRenderTarget[0], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));

	// next
	commonHeapHandle.Offset(DESCRIPTOR_COUNT_PER_DRAW,m_commonDescriptorSize);					
	srvDest0.Offset(DESCRIPTOR_COUNT_PER_DRAW,m_commonDescriptorSize);	
	
	// pass 2, Blur X axis
	pCommandList->SetGraphicsRootDescriptorTable(0,commonHeapHandle);	// CBV : Default | SRV : srcSrv
	
	pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_ppRenderTarget[1], D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET));	
	
	pCommandList->OMSetRenderTargets(1,&rtv1,FALSE,NULL);

	// set srv0 with texture from pass 1
	pDevice->CopyDescriptorsSimple(1,srvDest0,srv0,D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
	
	pCommandList->SetPipelineState(m_pPipelineState[POST_PROCESS_TYPE_BLUR_X]);
	pCommandList->DrawInstanced(4,1,0,0);
	
	pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_ppRenderTarget[1], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));

	// next
	commonHeapHandle.Offset(DESCRIPTOR_COUNT_PER_DRAW,m_commonDescriptorSize);					
	srvDest0.Offset(DESCRIPTOR_COUNT_PER_DRAW,m_commonDescriptorSize);
	
	
	// pass 3, Blur Y axis
	pCommandList->SetGraphicsRootDescriptorTable(0,commonHeapHandle);	// CBV : Default | SRV : srcSrv
	
	pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_ppRenderTarget[0], D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET));	
	
	pCommandList->OMSetRenderTargets(1,&rtv0,FALSE,NULL);

	// set srv0 with texture from pass 2
	pDevice->CopyDescriptorsSimple(1,srvDest0,srv1,D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
	
	pCommandList->SetPipelineState(m_pPipelineState[POST_PROCESS_TYPE_BLUR_Y]);
	pCommandList->DrawInstanced(4,1,0,0);
	
	pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_ppRenderTarget[0], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ));

	// next
	commonHeapHandle.Offset(DESCRIPTOR_COUNT_PER_DRAW,m_commonDescriptorSize);					
	srvDest0.Offset(DESCRIPTOR_COUNT_PER_DRAW,m_commonDescriptorSize);

	return TRUE;
}

답글 남기기

댓글을 게시하려면 다음의 방법 중 하나를 사용하여 로그인 하세요:

WordPress.com 로고

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

Twitter 사진

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

Facebook 사진

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

%s에 연결하는 중