1. 텍스쳐 생성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | CD3D11_TEXTURE2D_DESC desc; desc.Width = width; desc.Height = height; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = rtv_format; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; auto hr = d3d_device->CreateTexture2D(&desc, nullptr, &rtvTexture); | cs |
위는 빈 텍스쳐를 생성하는 코드이다.
CreateTexture2D 의 nullptr 이 D3D11_SUBRESOURCE_DATA 가 들어가는 곳으로, 특정 텍스쳐를 생성하고 싶다면 이 자료형에 원하는 데이터를 넣으면 된다.
여기서 Mapping 에 중요한 부분이 Usage 랑 CPUAccessFlags 그리고 BindFlags 이다.
https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_usage
https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_cpu_access_flag
msdn 에 잘 정리되어 있다.
1. CPU READ/WRITE
Mapping 에서 우리가 관심 있는 것은, CPU READ/WRITE, GPU READ/WRITE 이다.
CPU 는 알기 쉬운데, GPU READ/WRITE 는 무엇인가?
일단 가장 많이 쓰이는 것은 shader 의 input / output 이다.
하지만 이것만 있는 것이 아니라, copy 등의 연산도 gpu 에서 가능하다.
여기서 우리는 shader 와 그 밖의 용도를 구분해야한다.
그 이유는 위 테이블이 잘 말해준다.
Staging 은 모든 것에서 read/write 가 가능한데, 왜 stage 는 안되는 것인가?
그 이유는 shader 의 input/output 은 안되지만 copy 등의 연산은 가능하기 때문이다.
그렇기 때문에 Dynamic 은 cpu -> gpu 로 Shader 에 cpu 로 데이터를 보낼 때 쓰이고,
Staging 은 만든 후에 Dynamic/Default/Immutable 의 데이터에서 복사한 후 쓰인다.
이러한 Shader 에서의 사용은 BindFlags 에서 지정한다.
D3D11_BIND_SHADER_RESOURCE 가 input, D3D11_BIND_RENDER_TARGET 가 output 이다.
이것 외에도 다른 플래그도 Staging 의 다른 용도의 input 또는 output 을 설정한다.
CPUAcessFlags 는 CPU_READ/WRITE 두개 밖에 없고 Usage 에 맞춰서 넣어주면 된다.
2. MAPPING
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | d3d_context->CopyResource(copy, texture); D3D11_MAPPED_SUBRESOURCE data; HRESULT hr = d3d_context->Map(rtvcopy, 0, D3D11_MAP::D3D11_MAP_READ, 0, &data); { UCHAR* pTexels = (UCHAR*)data.pData; uint width = desc.width; uint height = desc.height; uint pixelSize = bitperpixel / 8; uint index = 0; for(int row = 0 ; row < height ; row++) { for(int col = 0 ; col < width ; col++) { uint index = row * data.RowPitch + col * 4; _rgba = pTexels[index] | pTexels[index+1] << 8 | pTexels[index+2] << 16 | pTexels[index+3] << 24; } } } d3d_context->Unmap(copy, 0); | cs |
위 코드는 texture 라는 Texture2D 에서 copy 로 복사 후, 데이터를 읽는 코드이다.
copy 는 당연히 cpu 에서 읽고 있으므로 Usage 는 Staging 이어야 한다.
CopyResource 함수가 device context 에서 실행되는 것을 보자.
위에서 말한대로 gpu 에서 copy 가 실행되는 것을 보여준다.
그렇게 복사한 copy 를 가지고 device context 는 Map, UnMap 을 실행한다.
Map - UnMap 사이에서 그 데이터가 gpu 에서 사용되지 못하도록 Lock 이 걸린다.
그 상태에서 우리는 cpu 에서 데이터를 사용할 수 있는 것이다.
그렇게 Lock 이 걸린 데이터는 D3D11_MAPPED_SUBRESOURCE 자료형으로 나온다.
그 자료형은 pData, RowPitch, DepthPitch 로 이루어져 있다.
pData 는 원하는 데이터의 시작 주소를, RowPitch/DepthPicth 는 byte 단위 크기를 말한다.
그런데 그 크기에는 약간의 패딩이 있어서, 우리가 지정한 텍스쳐의 크기와는 약간 다르다.
지정한 크기가 desc.width, desc.height 에 있다고 하면,
desc.width < RowPitch ( padding 이 들어감 )
desc.height = DepthPitch / desc.width
이런 상황이기 때문이다.
그래서 우리가 mapped data 의 인덱스를 조사하기 위해선 원래의 width, height 가 필요하다.
padding 이 들어간건 row 마다 있기 때문에, row, col 이 원하는 텍스쳐의 좌표라면
uint index = row * data.RowPitch + col * 4;
이렇게 원하는 픽셀의 시작 인덱스를 구할 수 있다.