Skip to content

ResourceUploadBatch

Chuck Walbourn edited this page Jun 22, 2018 · 54 revisions

This provides a helper for uploading resources such as textures to GPU memory. This class also handles automatic generation of mipmaps using shaders on the GPU.

Related tutorial: Sprites and textures

Header

#include "ResourceUploadBatch.h"

Usage

This helper is typically used during load and setup as follows which ends with a wait to ensure the GPU is ready before rendering is started. You start with a call to Begin, and then queue one or more upload operations. The End method returns a C++11 std::future which you use to complete the upload asynchronously.

ResourceUploadBatch upload(device);

upload.Begin();

DX::ThrowIfFailed(
    CreateDDSTextureFromFile(device, upload, L"mytexture.dds",
        tex.ReleaseAndGetAddressOf())
);

spriteBatch = std::make_unique<SpriteBatch>(device, upload, pd);

spriteFont = std::make_unique<SpriteFont>(device, upload,
    L"myfont.spritefont",
    resourceDescriptors->GetCpuHandle(Descriptors::TextFont),
    resourceDescriptors->GetGpuHandle(Descriptors::TextFont));

...

// Upload the resources to the GPU.
auto finish = upload.End(commandQueue);

// Wait for the upload thread to terminate
finish.wait();

You can also use the class to upload data to your own manually created resources which need to be in the D3D12_RESOURCE_STATE_COPY_DEST state. The helper supports queuing a resource barrier to transition the state after uploading using the Transition method.

ResourceUploadBatch upload(device);

upload.Begin();

auto desc = CD3DX12_RESOURCE_DESC(
    D3D12_RESOURCE_DIMENSION_TEXTURE2D,
    D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
    c_texture_size, c_texture_size, 1, 1,
    DXGI_FORMAT_R8G8_SNORM,
    1, 0,
    D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE);

CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);

DX::ThrowIfFailed(device->CreateCommittedResource(
    &defaultHeapProperties,
    D3D12_HEAP_FLAG_NONE,
    &desc,
    D3D12_RESOURCE_STATE_COPY_DEST,
    nullptr,
    IID_GRAPHICS_PPV_ARGS(tex.ReleaseAndGetAddressOf())));

D3D12_SUBRESOURCE_DATA initData = { mydata, c_texture_size * 2, 0 };
upload.Upload(tex.Get(), 0, &initData, 1);

upload.Transition(tex.Get(),
    D3D12_RESOURCE_STATE_COPY_DEST,
    D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);

...

// Upload the resources to the GPU.
auto finish = upload.End(commandQueue);

// Wait for the upload thread to terminate
finish.wait();

The data submitted to Upload is copied to a temporary D3D12_HEAP_TYPE_UPLOAD resource which is released when the upload is complete, so you don't need to keep the source buffer active beyond the call to Upload.

Generating mipmaps

DirectX 11 supported auto-generation of mipmaps for specific formats. This feature relied entirely on the driver, so the quality of auto-generated mipmaps was highly variable. DirectX 12 does not implement this feature, leaving it as an "exercise to the implementer". DirectX Tool Kit does this with ResourceUploadBatch.

To use it, you must create the texture with reserved mipmaps in the D3D12_RESOURCE_STATE_COPY_DEST state, load the image data into top-level mip, transition the resource to the D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE state, and then queue the mipmap generation using GenerateMips as follows:

ResourceUploadBatch upload(device);

upload.Begin();

auto desc = CD3DX12_RESOURCE_DESC(
    D3D12_RESOURCE_DIMENSION_TEXTURE2D,
    D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
    c_texture_size, c_texture_size, 1, c_mipmap_count,
    DXGI_FORMAT_R8G8B8A8_UNORM,
    1, 0,
    D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE);

CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT);

DX::ThrowIfFailed(device->CreateCommittedResource(
    &defaultHeapProperties,
    D3D12_HEAP_FLAG_NONE,
    &desc,
    D3D12_RESOURCE_STATE_COPY_DEST,
    nullptr,
    IID_GRAPHICS_PPV_ARGS(tex.ReleaseAndGetAddressOf())));

D3D12_SUBRESOURCE_DATA initData = { mydata, c_texture_size * 4, 0 };
upload.Upload(tex.Get(), 0, &initData, 1);

upload.Transition(tex.Get(),
    D3D12_RESOURCE_STATE_COPY_DEST,
    D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);

upload.GenerateMips(tex.Get());

...

// Upload the resources to the GPU.
auto finish = upload.End(commandQueue);

// Wait for the upload thread to terminate
finish.wait();

The GenerateMips function uses a DirectCompute shader to perform the mip-generation using bi-linear interpolation. The resource format must be UAV compatible (RGBA, F16, F32, etc.), BGRA, BGRX, RGBA sRGB, or BGRA sRGB. Otherwise a C++ exception is generated.

Note: High-quality mipmap generation is best done offline, stored in DDS files, and then loaded in full at a runtime using DDSTextureLoader.

Loading buffers

In addition to the texture functionality, you can also use this class to upload buffer data from GraphicsMemory allocated upload heap memory.

ResourceUploadBatch upload(device);

upload.Begin();

// Copy data into the upload heap
SharedGraphicsResource vbUpload = m_graphicsMemory->Allocate(vertexBufferSize);
memcpy(vbUpload.Memory(), /* source data */, vertexBufferSize);

auto desc = CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize);

CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_DEFAULT);
DX::ThrowIfFailed(device->CreateCommittedResource(
    &heapProperties,
    D3D12_HEAP_FLAG_NONE,
    &desc,
    D3D12_RESOURCE_STATE_COPY_DEST,
    nullptr,
    IID_PPV_ARGS(vertexBuffer.GetAddressOf())
));

upload.Upload(vertexBuffer.Get(), vbUpload);

upload.Transition(vertexBuffer.Get(),
    D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);

...

// Upload the resources to the GPU.
auto finish = upload.End(commandQueue);

// Wait for the upload thread to terminate
finish.wait();

Threading model

Each ResourceUploadBatch instance only supports submitting content from one thread at a time, but you can simultaneously submit content on multiple threads if you create a separate ResourceUploadBatch instance per command-list.

Work Submission in Direct3D 12

Remarks

Resource uploading is done for 'static' resources where the data is going to reside in GPU memory and be reused. For 'dynamic' data explicit uploading is not needed as the memory is allocated by GraphicsMemory, is both accessible to CPU and GPU, and will be released once the frame is completed.

For Use

  • Universal Windows Platform apps
  • Windows desktop apps
  • Windows 11
  • Windows 10
  • Xbox One
  • Xbox Series X|S

Architecture

  • x86
  • x64
  • ARM64

For Development

  • Visual Studio 2022
  • Visual Studio 2019 (16.11)
  • clang/LLVM v12 - v18
  • MinGW 12.2, 13.2
  • CMake 3.20

Related Projects

DirectX Tool Kit for DirectX 11

DirectXMesh

DirectXTex

DirectXMath

Tools

Test Suite

Model Viewer

Content Exporter

DxCapsViewer

See also

DirectX Landing Page

Clone this wiki locally