버퍼를 통해 텍스처 데이터 업로드

2D 또는 3D 질감 데이터를 업로드하는 것은 애플리케이션이 행 피치에 관련된 데이터 정렬에 더 주의해야 한다는 점을 제외하고 1D 데이터를 업로드하는 것과 비슷합니다. 버퍼는 그래픽 파이프라인의 여러 부분에서 직각으로 동시에 사용할 수 있으며 매우 유연합니다.

버퍼를 통해 텍스처 데이터 업로드

애플리케이션은 ID3D12GraphicsCommandList::CopyTextureRegion 또는 ID3D12GraphicsCommandList::CopyBufferRegion을 통해 데이터를 업로드해야 합니다. 텍스처 데이터는 대규모이며 반복적으로 액세스하기 쉬우며, 다른 리소스 데이터보다 개선된 비선형 메모리 레이아웃의 캐시 일관성을 활용합니다. D3D12에서 버퍼를 사용할 경우 메모리 정렬 요구 사항이 충족된다면 애플리케이션은 리소스 데이터 복사와 관련된 데이터 배치 및 배열을 완전히 제어합니다.

샘플에서는 애플리케이션이 2D 데이터를 버퍼에 배치하기 전에 1D로 간단히 평면화하는 경우를 보여 줍니다. MIP 맵 2D 시나리오의 경우, 애플리케이션은 각 하위 리소스를 개별적으로 평면화하고 1D 하위 할당 알고리즘을 신속하게 사용하거나, 좀 더 복잡한 2D 하위 할당 방법을 사용하여 비디오 메모리 사용률을 최소화할 수 있습니다. 첫 번째 방법이 좀 더 간단해서 더 자주 사용됩니다. 두 번째 방법은 데이터를 디스크로 또는 네트워크를 통해 압축할 때 유용할 수 있습니다. 두 경우 모두, 애플리케이션은 여전히 각 하위 리소스에 대해 복사 API를 호출해야 합니다.

// Prepare a pBitmap in memory, with bitmapWidth, bitmapHeight, and pixel format of DXGI_FORMAT_B8G8R8A8_UNORM. 
//
// Sub-allocate from the buffer for texture data.
//

D3D12_SUBRESOURCE_FOOTPRINT pitchedDesc = { 0 };
pitchedDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
pitchedDesc.Width = bitmapWidth;
pitchedDesc.Height = bitmapHeight;
pitchedDesc.Depth = 1;
pitchedDesc.RowPitch = Align(bitmapWidth * sizeof(DWORD), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);

//
// Note that the helper function UpdateSubresource in D3DX12.h, and ID3D12Device::GetCopyableFootprints 
// can help applications fill out D3D12_SUBRESOURCE_FOOTPRINT and D3D12_PLACED_SUBRESOURCE_FOOTPRINT structures.
//
// Refer to the D3D12 Code example for the previous section "Uploading Different Types of Resources"
// for the code for SuballocateFromBuffer.
//

SuballocateFromBuffer(
    pitchedDesc.Height * pitchedDesc.RowPitch,
    D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT
    );

D3D12_PLACED_SUBRESOURCE_FOOTPRINT placedTexture2D = { 0 };
placedTexture2D.Offset = m_pDataCur – m_pDataBegin;
placedTexture2D.Footprint = pitchedDesc;

//
// Copy texture data from DWORD* pBitmap->pixels to the buffer
//

for (UINT y = 0; y < bitmapHeight; y++)
{
  UINT8 *pScan = m_pDataBegin + placedTexture2D.Offset + y * pitchedDesc.RowPitch;
  memcpy( pScan, &(pBitmap->pixels[y * bitmapWidth]), sizeof(DWORD) * bitmapWidth );
}

//
// Create default texture2D resource.
//

D3D12_RESOURCE_DESC  textureDesc { ... };

CComPtr<ID3D12Resource> texture2D;
d3dDevice->CreateCommittedResource( 
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), 
        D3D12_HEAP_FLAG_NONE, &textureDesc, 
        D3D12_RESOURCE_STATE_COPY_DEST, 
        nullptr, 
        IID_PPV_ARGS(&texture2D) );

//
// Copy heap data to texture2D.
//

commandList->CopyTextureRegion( 
        &CD3DX12_TEXTURE_COPY_LOCATION( texture2D, 0 ), 
        0, 0, 0, 
        &CD3DX12_TEXTURE_COPY_LOCATION( m_spUploadHeap, placedTexture2D ), 
        nullptr );

도우미 구조 CD3DX12_HEAP_PROPERTIESCD3DX12_TEXTURE_COPY_LOCATIONCreateCommittedResourceCopyTextureRegion 메서드를 사용합니다.

복사

D3D12 메서드를 사용하여 애플리케이션은 D3D11 UpdateSubresource, CopySubresourceRegion 및 리소스 초기 데이터를 바꿀 수 있습니다. 단일 3D 하위 리소스에 상응하는 행 중심 텍스처 데이터는 버퍼 리소스에 있을 수 있습니다. CopyTextureRegion은 버퍼의 해당 텍스처 데이터를 알 수 없는 텍스처 레이아웃의 텍스처 리소스로, 또는 그 반대로 복사할 수 있습니다. 애플리케이션은 자주 액세스되는 GPU 리소스를 채우기 위해 이러한 유형의 방법을 선호하여 CPU 액세스 권한이 없는 DEFAULT 힙에서 자주 액세스되는 GPU 리소스를 만들면서, UPLOAD 힙에서 대규모 버퍼를 만듭니다. 이러한 방법은 UMA 아키텍처에 손상을 주지 않으면서 개별 GPU 및 대량의 해당 CPU 액세스 불가 메모리를 효율적으로 지원합니다.

다음 두 가지 상수에 유의합니다.

const UINT D3D12_TEXTURE_DATA_PITCH_ALIGNMENT = 256;
const UINT D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT = 512;

매핑 및 매핑 해제

MapUnmap은 여러 스레드에서 안전하게 호출할 수 있습니다. 첫 번째 Map 호출은 리소스에 대해 CPU 가상 주소 범위를 할당합니다. 마지막 Unmap 호출은 CPU 가상 주소 범위 할당을 취소합니다. CPU 가상 주소는 일반적으로 애플리케이션으로 반환됩니다.

다시 읽기 힙의 리소스를 통해 CPU 및 GPU 간에 데이터가 전달될 때마다 MapUnmap을 사용하여 D3D12가 지원되는 모든 시스템을 지원해야 합니다. 범위를 최대한 엄격하게 유지하면 범위가 필요한 시스템에서 효율성을 최대화합니다( D3D12_RANGE 참조).

디버깅 도구의 성능은 모든 Map / Unmap 호출에서 범위를 정확하게 사용할 수 있을 뿐만 아니라 CPU 수정이 더 이상 이루어지지 않을 때 리소스 매핑을 해제하는 애플리케이션의 이점을 누릴 수 있습니다.

Map(DISCARD 매개 변수를 설정하지 않음)를 사용하여 리소스의 이름을 바꾸는 D3D11 메서드는 D3D12에서 지원되지 않습니다. 애플리케이션은 리소스 이름 바꾸기를 직접 구현해야 합니다. 모든 호출은 암시적으로 NO_OVERWRITE 다중 스레드입니다. CPU를 사용하여 데이터에 액세스하기 전에 명령 목록에 포함된 모든 관련 GPU 작업이 완료되었는지 확인하는 것은 애플리케이션의 책임입니다. Map에 대한 D3D12 호출은 명령 버퍼를 암시적으로 플러시하지 않으며, GPU가 작업을 완료할 때까지 기다리는 것을 차단하지 않습니다. 따라서 일부 시나리오에서는 MapUnmap이 최적화될 수도 있습니다.

버퍼 맞춤

버퍼 맞춤 제한:

  • 선형 하위 리소스 복사는 512바이트(행 피치가 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT 바이트에 맞춰 정렬됨)에 맞춰야 합니다.
  • 상수 데이터 읽기는 힙의 시작 부분부터 256바이트의 배수여야 합니다(예: 256바이트가 맞춰진 주소부터).
  • 인덱스 데이터 읽기는 인덱스 데이터 형식 크기의 배수여야 합니다(예: 데이터에 자연스럽게 맞춰진 주소부터).
  • ID3D12GraphicsCommandList::ExecuteIndirect 데이터는 4의 배수인 오프셋(즉, DWORD가 정렬된 주소에서만)이어야 합니다.