공부중

[DirectX12]Hello Wolrd Sample - D3D12HelloTexture - 6 본문

Programing/DirectX

[DirectX12]Hello Wolrd Sample - D3D12HelloTexture - 6

곤란 2018. 6. 5. 17:44
반응형
	// Note: ComPtr은 CPU 개체이지만 이 리소스는 이를 참조하는 명령 목록이 
	// GPU에서 실행을 마칠 때까지 범위에 있어야합니다.
	// 자원이 조기에 파괴되지 않도록
	// 이 방법의 끝에서 GPU를 플러시합니다.
	ComPtr<ID3D12Resource> textureUploadHeap;

	// Create the texture.
	{
		// Describe and create a Texture2D.
		D3D12_RESOURCE_DESC textureDesc = {};
		textureDesc.MipLevels = 1;
		textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		textureDesc.Width = TextureWidth;
		textureDesc.Height = TextureHeight;
		textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
		textureDesc.DepthOrArraySize = 1;
		textureDesc.SampleDesc.Count = 1;
		textureDesc.SampleDesc.Quality = 0;
		textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;

		ThrowIfFailed(m_device->CreateCommittedResource(
			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
			D3D12_HEAP_FLAG_NONE,
			&textureDesc,
			D3D12_RESOURCE_STATE_COPY_DEST,
			nullptr,
			IID_PPV_ARGS(&m_texture)));

		const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.Get(), 0, 1);

		// Create the GPU upload buffer.
		ThrowIfFailed(m_device->CreateCommittedResource(
			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
			D3D12_HEAP_FLAG_NONE,
			&CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
			D3D12_RESOURCE_STATE_GENERIC_READ,
			nullptr,
			IID_PPV_ARGS(&textureUploadHeap)));

		// 중간 업로드 힙에 데이터를 복사 한 다음
		// 업로드 힙에서 Texture2D로 복사본을 예약하십시오.
		std::vector<UINT8> texture = GenerateTextureData();

		D3D12_SUBRESOURCE_DATA textureData = {};
		textureData.pData = &texture[0];
		textureData.RowPitch = TextureWidth * TexturePixelSize;
		textureData.SlicePitch = textureData.RowPitch * TextureHeight;

		UpdateSubresources(m_commandList.Get(), m_texture.Get(), textureUploadHeap.Get(), 0, 0, 1, &textureData);
		m_commandList->ResourceBarrier(1, 
					       &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), 
										     D3D12_RESOURCE_STATE_COPY_DEST, 
										     D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));

		// 텍스처에 대한 SRV를 설명하고 생성하십시오.
		D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
		srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
		srvDesc.Format = textureDesc.Format;
		srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
		srvDesc.Texture2D.MipLevels = 1;
		m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_srvHeap->GetCPUDescriptorHandleForHeapStart());
	}

 

이번 코드는 꽤 긴 코드이며 텍스쳐 생성에 관련된 코드이다.

주석은 번역기를 돌렸다.

 

	// Note: ComPtr은 CPU 개체이지만 이 리소스는 이를 참조하는 명령 목록이 
	// GPU에서 실행을 마칠 때까지 범위에 있어야합니다.
	// 자원이 조기에 파괴되지 않도록
	// 이 방법의 끝에서 GPU를 플러시합니다.
	ComPtr<ID3D12Resource> textureUploadHeap;

제일 위에 있는 ComPtr로 ID3D12Resource 형의 textureUploadHeap을 만들었고 아래의 코드에서 업로드 버퍼로 쓰이는 모습이 보인다.

 

		// Describe and create a Texture2D.
		D3D12_RESOURCE_DESC textureDesc = {};
		textureDesc.MipLevels = 1;
		textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		textureDesc.Width = TextureWidth;
		textureDesc.Height = TextureHeight;
		textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
		textureDesc.DepthOrArraySize = 1;
		textureDesc.SampleDesc.Count = 1;
		textureDesc.SampleDesc.Quality = 0;
		textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;

일단 구문 안으로 들어가면 D3D12_RESOURCE_DESC형으로 사용하려는 텍스쳐에 관련된 정보들을 서술하고 있다.

 

		ThrowIfFailed(m_device->CreateCommittedResource(
			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
			D3D12_HEAP_FLAG_NONE,
			&textureDesc,
			D3D12_RESOURCE_STATE_COPY_DEST,
			nullptr,
			IID_PPV_ARGS(&m_texture)));
 

CreateCommittedResource는 자원을 생성하고 지정된 속성들에 부합하는 힙에 그 자원을 맡긴다고 한다(commit)

첫번째 인자를 보면 &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT) 로 주어줬는데.

D3D12_HEAP_TYPE_DEFAULT는 기본 힙이며 전적으로 GPU가 접근할 자원들이 담긴다고 한다.

다른 타입을 보려면 D3D12_HEAP_TYPE enumeration - MSDN 을 살펴보자

 

두번째 인자는 자원을 맡길 힙이 가졌으면 하는 속성들을 나타내는 추가적인 플래그들이다.

플래그들의 정보를 보고 싶으면 D3D12_HEAP_FLAGS enumeration - MSDN 을 살펴보도록 하자

 

세번째 인자는 생성하고자 하는 자원을 서술하는 D3D12_RESOURCE_DESC 인스턴스의 포인터이다

여기서는 바로 위에서 작성한 textureDesc의 주소를 넘겨주었다.

 

네번째 인자는 자원에는 상태(state)가 있는데 자원의 초기 상태를 지정한다.

상태의 종류와 설명을 보고 시으면 D3D12_RESOURCE_STATES enumeration - MSDN을 살펴보자

 

다섯번째 인자는 자원 지우기에 최적화된 값을 나타내는 D3D12_CLEAR_VALUE 구조체를 가리키는 포인터이다.

따로 설정하지 않으러면 null을 지정하면 된다고 한다.

 

		const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.Get(), 0, 1);

		// Create the GPU upload buffer.
		ThrowIfFailed(m_device->CreateCommittedResource(
			&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
			D3D12_HEAP_FLAG_NONE,
			&CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
			D3D12_RESOURCE_STATE_GENERIC_READ,
			nullptr,
			IID_PPV_ARGS(&textureUploadHeap)));

 

다음 라인은 업로드할 버퍼의 사이즈를 UINT64에 저장했다.

GetRequiredIntermediateSize - MSDN는 데이터 업로드에 필요한 버퍼의 크기를 반환하는 함수이다.

 

그리고 하단에 GPU 업로드 버퍼를 생성하는데 위에서 사용한 CreateCommittedResource를 이용하고 있다.

첫번째 인자의 플래그로 D3D12_HEAP_TYPE_UPLOAD로 주었다.

첫번째 상태로는 D3D12_RESOURCE_STATE_GENERIC_READ를 주었다.

 

		// 중간 업로드 힙에 데이터를 복사 한 다음
		// 업로드 힙에서 Texture2D로 복사본을 예약하십시오.
		std::vector<UINT8> texture = GenerateTextureData();

		D3D12_SUBRESOURCE_DATA textureData = {};
		textureData.pData = &texture[0];
		textureData.RowPitch = TextureWidth * TexturePixelSize;
		textureData.SlicePitch = textureData.RowPitch * TextureHeight;

std::vector로 texture라는 변수를 만들고 GenerateTextureData에서 값을 받아오고 있다. 저 GenerateTextureData를 살펴보면...

 

std::vector D3D12HelloTexture::GenerateTextureData()
{
	const UINT rowPitch = TextureWidth * TexturePixelSize;
	const UINT cellPitch = rowPitch >> 3;		// The width of a cell in the checkboard texture.
	const UINT cellHeight = TextureWidth >> 3;	// The height of a cell in the checkerboard texture.
	const UINT textureSize = rowPitch * TextureHeight;

	std::vector data(textureSize);
	UINT8* pData = &data[0];

	for (UINT n = 0; n < textureSize; n += TexturePixelSize)
	{
		UINT x = n % rowPitch;
		UINT y = n / rowPitch;
		UINT i = x / cellPitch;
		UINT j = y / cellHeight;

		if (i % 2 == j % 2)
		{
			pData[n] = 0x00;	// R
			pData[n + 1] = 0x00;	// G
			pData[n + 2] = 0x00;	// B
			pData[n + 3] = 0xff;	// A
		}
		else
		{
			pData[n] = 0xff;	// R
			pData[n + 1] = 0xff;	// G
			pData[n + 2] = 0xff;	// B
			pData[n + 3] = 0xff;	// A
		}
	}p

	return data;
}

 

주석에 나온대로 간단한 체커보드 텍스쳐값을 가져온다...(애초에 이미지파일을 불러오는게 아니였다 -_-....)

이미지에서 긁어오든 뭐든 일단 저 코드가 하나의 이미지파일을 읽어다가 데이터를 긁어왔다고 생각해보자.

 

 

class D3D12HelloTexture : public DXSample
{
	// 생략...

	static const UINT TextureWidth = 256;
	static const UINT TextureHeight = 256;
	static const UINT TexturePixelSize = 4;	// The number of bytes used to represent a pixel in the texture.

	// 생략...

 

D3D12HelloTexture.h 에서 새로 추가된 부분중 하나인데 이 값들이 저 텍스쳐데이터를 가져오는데 쓰인다. 위에서부터 살펴보자..

 

	const UINT rowPitch = TextureWidth * TexturePixelSize;
	const UINT cellPitch = rowPitch >> 3;		// The width of a cell in the checkboard texture.
	const UINT cellHeight = TextureWidth >> 3;	// The height of a cell in the checkerboard texture.
	const UINT textureSize = rowPitch * TextureHeight;

 

Pitch는 여기 링크를 참조해보도록 해보자 ( 링크1 , 링크2 ) 실제 데이터로 변환했을때 실제 가로의 바이트? 정도?

(솔직히 말하자면 내가 텍스처에 관해서 공부를 해야한다 -_-... 공부를 하고 따로 글을 적든지 해서 정리를 해야 겠다)

 

 

	std::vector<UINT8> data(textureSize);
	UINT8* pData = &data[0];

 

vector로 UINT8 형으로 위에서 계산한 textureSize만큼 만들어 주었고

첫번째 주소가져오는 모습이다.

 

 

	for (UINT n = 0; n < textureSize; n += TexturePixelSize)
	{
		UINT x = n % rowPitch;
		UINT y = n / rowPitch;
		UINT i = x / cellPitch;
		UINT j = y / cellHeight;

		if (i % 2 == j % 2)
		{
			pData[n] = 0x00;	// R
			pData[n + 1] = 0x00;	// G
			pData[n + 2] = 0x00;	// B
			pData[n + 3] = 0xff;	// A
		}
		else
		{
			pData[n] = 0xff;	// R
			pData[n + 1] = 0xff;	// G
			pData[n + 2] = 0xff;	// B
			pData[n + 3] = 0xff;	// A
		}
	}

	return data;

 

이후로 반복문을 통해서 텍스처의 데이터를 넣어준다.

if문의 구역에는 검정색으로...

else문은 하얀색으로 ....

 

반복문을 모두 돌면 data를 리턴한다.

 

저 텍스쳐에 대해서는 공부를 해서 다시 정리를 해봐야겠다 -_-... (기초가 부족하니 왜 저럴까 고민만 계속했다.)

 

아무튼 GenerateTextureData는 텍스처 데이터를 리턴하므로 텍스쳐 데이터를 받아올수 있다.

 

그리고 하단에 D3D12_SUBRESOURCE_DATA형으로 textureData를 서술하고 있다.

D3D12_SUBRESOURCE_DATA structure - MSDN

 

		UpdateSubresources(m_commandList.Get(), m_texture.Get(), textureUploadHeap.Get(), 0, 0, 1, &textureData);
		m_commandList->ResourceBarrier(1, 
					       &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), 
										     D3D12_RESOURCE_STATE_COPY_DEST, 
										     D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
 

UpdateSubresources 위에서 작성한 하위리소스를 업데이트 하고

ResourceBarrier를 통해서 복사 상태에서 픽셀셰이더 상태로 전환 하고 있다.

 

		// 텍스처에 대한 SRV를 설명하고 생성하십시오.
		D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
		srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
		srvDesc.Format = textureDesc.Format;
		srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
		srvDesc.Texture2D.MipLevels = 1;
		m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_srvHeap->GetCPUDescriptorHandleForHeapStart());
 

D3D12_SHADER_RESOURCE_VIEW_DESC형의 구조체를 만들고 서술하고 있다

각각의 멤버에 대해서는 D3D12_SHADER_RESOURCE_VIEW_DESC structure - MSDN 을 참조하자

 

CreateShaderResourceView를 통해서 위에서 생성한 srvDesc를 넘겨주어서 셰이더 리소스 뷰를 생성하였다.

 

 

이 글은 너무 엉망진창이라 -_- 나중에 다시 작성해야될 판이다...

으으으으....

 

열심히 공부해야지 ㅠㅠ

 

다음 코드는 GPU와 동기화 하는 부분이다.

저번 프로젝트와 차이가 없으므로 간단히 끝이날것같다...

 

다음글에서...

 

 

 

 

반응형